Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.30;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.054 c
2-1128933624
qwerty2K3
2005-10-10 12:40
2005.10.30
Как программно отправить по сети - net send "привет!" ?


1-1128811063
none
2005-10-09 02:37
2005.10.30
ZoneAlarm


3-1127207552
Starcom
2005-09-20 13:12
2005.10.30
Как мне подсчитать разницу в формате (Год, лет) с текущей датой?


2-1128594808
Del_programmer
2005-10-06 14:33
2005.10.30
строки


4-1125065609
heady
2005-08-26 18:13
2005.10.30
получить последний(текущий)адрес из открытого IE