Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];

Вниз

дефрагментация   Найти похожие ветки 

 
NightLord ©   (2005-10-02 01:03) [0]

Всем привет! Подскажите как можно записать на винчестер файл без фрагментов? Заранее благодарю.


 
Германн ©   (2005-10-02 01:29) [1]

А зачем? Объясни.
Поскольку варианты есть, но нет уверенности, что они тебе подойдут. :(


 
Chuvak ©   (2005-10-02 01:32) [2]

NightLord ©   (02.10.05 1:03)
Подскажите как можно записать на винчестер файл без фрагментов?

хм...если файл большой по размеру, то придётся попотеть...А такое в принципе возможно?


 
Германн ©   (2005-10-02 01:38) [3]

2 Chuvak ©   (02.10.05 01:32) [2]
> А такое в принципе возможно?

ГАРАНТИРУЮ! В принципе возможно. НО...


 
Chuvak ©   (2005-10-02 01:43) [4]

Германн ©   (02.10.05 1:38) [3]
В принципе возможно. НО...

НУ? Интересно же...пусть даже гипотетически...


 
Германн ©   (2005-10-02 01:50) [5]

Ну если интересно, то пожалуйста - Вариант 1:  После format буква_диска: первый файл запишется без фрагментации! :)


 
YurikGL ©   (2005-10-02 01:51) [6]

Можно сначала записать файл, а потом запустить дефрагментатор через shellexecute :)


 
Chuvak ©   (2005-10-02 01:57) [7]

YurikGL ©   (02.10.05 1:51) [6]
Можно сначала записать файл, а потом запустить дефрагментатор через shellexecute :)

вопрос был как можно записать на винчестер файл, а не как избавится от фрагментов....
А какие-нить серъёзные варианты ещё есть? ;)


 
Германн ©   (2005-10-02 02:07) [8]

2 Chuvak ©   (02.10.05 01:57) [7]
> А какие-нить серъёзные варианты ещё есть? ;)


Серьёзные варианты могут найтись. Но безгеморройные - врядли. Поэтому я и просил уточнить задачу.


 
Chuvak ©   (2005-10-02 02:10) [9]

Германн ©   (02.10.05 2:07) [8]
Серьёзные варианты могут найтись.

Всё ходим вокруг да около...а ничего так и не услышали...


 
drpass ©   (2005-10-02 02:11) [10]


> После format буква_диска: первый файл запишется без фрагментации!
>  :)

На 100% это справедливо только на FAT

> А какие-нить серъёзные варианты ещё есть? ;)

На FAT - открыть диск для прямого доступа с помощью CreateFile, проанализировать его структуру, найти там подходящий непрерывный кусок свободного места, вписать туда свой файл и вручную же внести соответствующие изменения в таблицы размещения. На NTFS, если мне память не изменяет, это не требуется. Ее стратегия размещения файлов и так предполагает запихивание их по возможности целиком в свободные области.
Кстати, а зачем это неблагодарное занятие?


 
vrem   (2005-10-02 09:27) [11]

При записи на диск Windows просматривает свободные участки диска, если найден свободный участок размером больше, чем "минимальный размер свободного "участка" диска, то запись начинается в этом участке. если размер меньше, то windows продолжает дальше искать свободный "кусок"
Этот "минимальный размер" задаётся, как раз для уменьшения дефрагментации.


 
NightLord ©   (2005-10-02 10:25) [12]

> Германн ©   (02.10.05 01:29) [1]

Я хочу сделадь что-то подобное виндовому дефрагментатору (самому интересно).


 
Anatoly Podgoretsky ©   (2005-10-02 13:18) [13]

Такое возможно только в однозадачной системе типа ДОС, во всех остальных не гарантируется. Система тоже желает писать на диск.


 
drpass ©   (2005-10-02 13:38) [14]

Для дефрагментации есть специальный API


 
homm ©   (2005-10-02 14:49) [15]

2 drpass

A что за API такой? Где под него можно заголовки, примеры найти. Раскрой тему если не трудно, мне тоже было бы интересно узнать.


 
drpass ©   (2005-10-02 14:55) [16]

Через I/O Control - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/defragmenting_files.asp


 
NightLord ©   (2005-10-02 15:19) [17]

А можно проделать дефрагментацию без использвания WinApi к примеру из DOS"а ?


 
alexbou   (2005-10-02 16:39) [18]

хм.... Озадачился - и вот что набросил за час-два ползания по документации + написании кода...

Предупреждаю - тут много сделано на допущении (например что нет интенсивной записи произвольным образом другими программами :))

Итак - задачи:
Создать файл размером 1 гигабайт без фрагментации

1) получаем размер кластера
2) вычисляем кол-во нужных кластеров
3) ищем блок свободного пространства (получаем номер стартового кластера для этого блока)
4) создаем файл (размером 1 байт =) - почему один а не ноль? потому что нулевые файлы не занимают места вообще (ну кроме как в MFT=)))
5) перемещаем файл-кластер в начало блока
6) расширяем =) вуаля


program creat_notfrag_file;

{$APPTYPE CONSOLE}

uses
 Windows, SysUtils, Math;

const
 FileNameToCreate = "d:\temp\data.dat";
 FileSizeToCreate: Int64 = 1*1024*1024*1024;

const
 FILE_READ_ATTRIBUTES          = $0080;
 FILE_WRITE_ATTRIBUTES         = $0100;

 FSCTL_GET_NTFS_VOLUME_DATA    = $00090064;
 FSCTL_GET_VOLUME_BITMAP       = $0009006F;
 FSCTL_GET_RETRIEVAL_POINTERS  = $00090073;
 FSCTL_MOVE_FILE               = $00090074;

// no comments =)
function OpenVolume(Drive: Char): THandle;
var
 DriveName: PChar;
begin
 DriveName := PChar("\\.\" + Drive + ":");
 Result := CreateFile(DriveName,
     GENERIC_READ or GENERIC_WRITE,
     FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
     0, 0);
end;

type
 TNtfsVolumeDataBuffer = record
   VolumeSerialNumber            : Int64;
   NumberSectors                 : Int64;
   TotalClusters                 : Int64;
   FreeClusters                  : Int64;
   TotalReserved                 : Int64;
   BytesPerSector                : DWORD;
   BytesPerCluster               : DWORD;
   BytesPerFileRecordSegment     : DWORD;
   ClustersPerFileRecordSegment  : DWORD;
   MftValidDataLength            : Int64;
   MftStartLcn                   : Int64;
   Mft2StartLcn                  : Int64;
   MftZoneStart                  : Int64;
   MftZoneEnd                    : Int64;
 end;

// получить информацию о томе
// свободных кластеров и размер кластера
function GetClustersInfoOfVolume(
   VolumeHandle: THandle;
   out FreeClusters: Int64;
   out SizeOfCluster: DWORD
 ): Boolean;
var
 NtfsVolumeDataBuffer: TNtfsVolumeDataBuffer;
 RetSize: DWORD;
begin
 Result := false;
 if DeviceIoControl(VolumeHandle, FSCTL_GET_NTFS_VOLUME_DATA,
     nil, 0, @NtfsVolumeDataBuffer, sizeof(NtfsVolumeDataBuffer),
     RetSize, nil) then
   begin
     FreeClusters := NtfsVolumeDataBuffer.FreeClusters;
     SizeOfCluster := NtfsVolumeDataBuffer.BytesPerCluster;
     Result := true;
   end;
end;

const
 BufferSize = 4096;
type
 TVolumeBitmapBuffer = record
   StartingLcn : Int64;
   BitmapSize  : Int64;
   Buffer      : array [0..BufferSize] of Byte;
 end;
 PVolumeBitmapBuffer = ^TVolumeBitmapBuffer;

// возвращает LCN для первого же найденого блока
// свободных кластеров, куда влезет файл
// !!! Это функция не учитывает сам файл, поэтому
// не юзать после создания файла заданного размера
function SearchFreeSpaceBlockForFileSpawn(
   VolumeHandle: THandle;
   ReqBlockSizeInClusters: Cardinal
 ): Cardinal;
var
 StartLcn: Int64;
 Bitmap: TVolumeBitmapBuffer;
 pBitmap: PVolumeBitmapBuffer;
 RetSize: DWORD;
 RetStatus: Cardinal;
 StartFree: Int64;
 NumFree: Int64;
 idx: Int64;
begin
 Result := Cardinal(-1);

 StartFree := -1;
 NumFree := 0;

 StartLcn := 0;
 pBitmap := @Bitmap;

 FillChar(Bitmap, SizeOf(Bitmap), 0);

 repeat
   SetLastError(0);
   DeviceIoControl(VolumeHandle, FSCTL_GET_VOLUME_BITMAP,
       @StartLcn, SizeOf(Int64),
       pBitMap, SizeOf(Bitmap), RetSize, nil);
   RetStatus := GetLastError;

   if (RetStatus <> 0) and (RetStatus <> ERROR_MORE_DATA) then
     begin
       Writeln("FSCTL_GET_VOLUME_BITMAP");
       Break;
     end;

   // обход ограничений компилятора на использования Int64  в циклах for
   idx := 0;
   while idx < Min(pBitmap.BitmapSize, BufferSize * 8) - 1 do
     begin
       if pBitmap.Buffer[idx div 8] and (1 shl (idx mod 8)) = 0 then
         begin
           if StartFree = -1 then
             begin
               StartFree := pBitmap.StartingLcn + idx;
               NumFree := 1;
             end
           else
             Inc(NumFree);
         end
       else
         StartFree := -1;

       if (StartFree <> -1) and (NumFree = ReqBlockSizeInClusters) then
         begin
           Result := StartFree;
           Writeln;
           Exit;
         end;

       Inc(idx);
     end;

   if RetStatus = ERROR_MORE_DATA then
     StartLcn := Bitmap.StartingLcn + BufferSize * 8
   else
     Break;

   Write(".");
 until False;

 Writeln;
end;

type
 TMovieFileData = record
   FileHandle: THandle;
   StartingVcn: Int64;
   StartingLcn: Int64;
   ClusterCount: DWORD;
 end;


 
alexbou   (2005-10-02 16:40) [19]



// Перемещает кластер файла
function MoveFileCluster(
   hVolume, hFile: THandle;
   VCN: Cardinal; LCN: Cardinal
 ): Boolean;
var
 MovieFileData: TMovieFileData;
 RetSize: DWORD;
begin
 with MovieFileData do
   begin
     FileHandle := hFile;
     StartingVcn := VCN;
     StartingLcn := LCN;
     ClusterCount := 1;
   end;

 Result := DeviceIoControl(hVolume, FSCTL_MOVE_FILE,
     @MovieFileData, SizeOf(TMovieFileData),
     nil, 0,
     RetSize, nil);
end;

// Создаем нужный файл нужного размера
function SpawnFile(
   hVolume: THandle;
   TargetCluster: Int64;
   FileName: &String; FileSize: DWORD
 ): Boolean;
var
 hFile: THandle;
begin
 Result := False;

 hFile := CreateFile(FileNameToCreate,
     FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES
     or GENERIC_READ or GENERIC_WRITE,
     FILE_SHARE_WRITE or FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
 if hFile = INVALID_HANDLE_VALUE then
   Exit;

 SetFilePointer(hFile, 1, nil, FILE_BEGIN);
 SetEndOfFile(hFile);
 FlushFileBuffers(hFile);
 CloseHandle(hFile);

 // перемещаем в нужный кластер (начало большого пространства)
 hFile := CreateFile(FileNameToCreate,
     FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES,
     FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
     OPEN_EXISTING, 0, 0);
 if hFile = INVALID_HANDLE_VALUE then
   Exit;

 if not MoveFileCluster(hVolume, hFile,
     0, TargetCluster) then
   begin
     Writeln("FSCTL_MOVE_FILE");
     Exit;
   end;
 FlushFileBuffers(hFile);
 CloseHandle(hFile);

 // расширяем файл
 hFile := CreateFile(FileNameToCreate,
     FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES
     or GENERIC_READ or GENERIC_WRITE,
     FILE_SHARE_WRITE or FILE_SHARE_WRITE, nil,
     OPEN_EXISTING, 0, 0);

 SetFilePointer(hFile, FileSize, nil, FILE_BEGIN);
 SetEndOfFile(hFile);
 FlushFileBuffers(hFile);

 CloseHandle(hFile);
end;

var
 VolumeHandle: THandle;
 FreeClusters: Int64;
 SizeOfCluster: DWORD;
 NeededClusters: DWORD;
 TargetCluster: Int64;

begin
 VolumeHandle := OpenVolume(FileNameToCreate[1]);
 if VolumeHandle = INVALID_HANDLE_VALUE then
   begin
     Writeln("OpenVolume");
     Exit;
   end;

 if not GetClustersInfoOfVolume(VolumeHandle,
     FreeClusters, SizeOfCluster) then
   begin
     Writeln("GetClustersInfoOfVolume");
     Exit;
   end;

 NeededClusters := FileSizeToCreate div SizeOfCluster
     + FileSizeToCreate mod SizeOfCluster;

 if (NeededClusters > FreeClusters) then
   begin
     Writeln("NeededClusters > FreeClusters");
     Exit;
   end;

 TargetCluster :=
     SearchFreeSpaceBlockForFileSpawn(VolumeHandle, NeededClusters + 1);

 if (TargetCluster = -1) then
   begin
     Writeln("TargetCluster = ?");
     Exit;
   end;

 SpawnFile(VolumeHandle, TargetCluster, FileNameToCreate, FileSizeToCreate);

 CloseHandle(VolumeHandle);
end.


 
homm ©   (2005-10-02 19:43) [20]

2 alexbou

Ну ты и заморил ;) клево блин. Только вот 2 вопроса
1) А чейто новоиспеченый файл в "Дефрагментатор диска" красным светится.
2) А на FAT то работает? Диск не грохнет?


 
alexbou   (2005-10-03 17:55) [21]

Для ФАТа нужно брать другую структуру для FSCTL_GET_VOLUME_BITMAP...

А что касательно фрагментации.... Мда.... Проверил - раз на раз не приходится, и у меня бывает фрагментация... =(


 
alexbou   (2005-10-03 18:06) [22]

drpass
> На NTFS, если мне память не изменяет, это не требуется.
> Ее стратегия размещения файлов и так предполагает запихивание
> их по возможности целиком в свободные области.


Увы и ах - это вовсе не гарантируется.... Иначе не было бы фрагментации файлов :) Была бы тогда просто фрагментация свободного пространства


 
drpass ©   (2005-10-03 23:28) [23]


> Увы и ах - это вовсе не гарантируется.... Иначе не было
> бы фрагментации файлов :)

Ну, до тех пор, пока это самое свободное место есть... Если учесть, что NTFS выбирает место "с запасом" - для возможного будущего роста файла, фрагментация начинает проявляться (и угрожающе быстро расти) примерно при 50%-60% заполнении тома



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.036 c
14-1128671022
Andry
2005-10-07 11:43
2005.10.30
Web-сервер


2-1128502645
Гость22
2005-10-05 12:57
2005.10.30
Как сделать, чтоб при вводе в Edit е, после 5-го и 10-го...


14-1128680608
__DATA__
2005-10-07 14:23
2005.10.30
Для чего исползуется протокол NetBios?


14-1129108254
Dush
2005-10-12 13:10
2005.10.30
Как узнать структуру файла?


3-1127279964
leonidus
2005-09-21 09:19
2005.10.30
Перехват нажатия "Применить" в TDBNavigator





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский