![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
дефрагментация [D7, WinXP]
NightLord © (2005-10-02 01:03:00)Всем привет! Подскажите как можно записать на винчестер файл без фрагментов? Заранее благодарю.
drpass (2005-10-03 23:28:00) [1]
> Увы и ах - это вовсе не гарантируется.... Иначе не было
> бы фрагментации файлов :)
Ну, до тех пор, пока это самое свободное место есть... Если учесть, что NTFS выбирает место "с запасом" - для возможного будущего роста файла, фрагментация начинает проявляться (и угрожающе быстро расти) примерно при 50%-60% заполнении тома
alexbou (2005-10-03 18:06:00) [2]drpass
> На NTFS, если мне память не изменяет, это не требуется.
> Ее стратегия размещения файлов и так предполагает запихивание
> их по возможности целиком в свободные области.
Увы и ах - это вовсе не гарантируется.... Иначе не было бы фрагментации файлов :) Была бы тогда просто фрагментация свободного пространства
alexbou (2005-10-03 17:55:00) [3]Для ФАТа нужно брать другую структуру для FSCTL_GET_VOLUME_BITMAP...
А что касательно фрагментации.... Мда.... Проверил - раз на раз не приходится, и у меня бывает фрагментация... =(
homm (2005-10-02 19:43:00) [4]2 alexbou
Ну ты и заморил ;) клево блин. Только вот 2 вопроса
1) А чейто новоиспеченый файл в "Дефрагментатор диска" красным светится.
2) А на FAT то работает? Диск не грохнет?
alexbou (2005-10-02 16:40:00) [5]
// Перемещает кластер файла
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.
alexbou (2005-10-02 16:39:00) [6]хм.... Озадачился - и вот что набросил за час-два ползания по документации + написании кода...
Предупреждаю - тут много сделано на допущении (например что нет интенсивной записи произвольным образом другими программами :))
Итак - задачи:
Создать файл размером 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;
NightLord (2005-10-02 15:19:00) [7]А можно проделать дефрагментацию без использвания WinApi к примеру из DOS'а ?
drpass (2005-10-02 14:55:00) [8]Через I/O Control - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/defragmenting_files.asp
homm (2005-10-02 14:49:00) [9]2 drpass
A что за API такой? Где под него можно заголовки, примеры найти. Раскрой тему если не трудно, мне тоже было бы интересно узнать.
drpass (2005-10-02 13:38:00) [10]Для дефрагментации есть специальный API
Anatoly Podgoretsky (2005-10-02 13:18:00) [11]Такое возможно только в однозадачной системе типа ДОС, во всех остальных не гарантируется. Система тоже желает писать на диск.
NightLord (2005-10-02 10:25:00) [12]> Германн © (02.10.05 01:29) [1]
Я хочу сделадь что-то подобное виндовому дефрагментатору (самому интересно).
vrem (2005-10-02 09:27:00) [13]При записи на диск Windows просматривает свободные участки диска, если найден свободный участок размером больше, чем "минимальный размер свободного "участка" диска, то запись начинается в этом участке. если размер меньше, то windows продолжает дальше искать свободный "кусок"
Этот "минимальный размер" задаётся, как раз для уменьшения дефрагментации.
drpass (2005-10-02 02:11:00) [14]
> После format буква_диска: первый файл запишется без фрагментации!
> :)
На 100% это справедливо только на FAT
> А какие-нить серъёзные варианты ещё есть? ;)
На FAT - открыть диск для прямого доступа с помощью CreateFile, проанализировать его структуру, найти там подходящий непрерывный кусок свободного места, вписать туда свой файл и вручную же внести соответствующие изменения в таблицы размещения. На NTFS, если мне память не изменяет, это не требуется. Ее стратегия размещения файлов и так предполагает запихивание их по возможности целиком в свободные области.
Кстати, а зачем это неблагодарное занятие?
Chuvak (2005-10-02 02:10:00) [15]Германн © (02.10.05 2:07) [8]
Серьёзные варианты могут найтись.
Всё ходим вокруг да около...а ничего так и не услышали...
Германн (2005-10-02 02:07:00) [16]2 Chuvak © (02.10.05 01:57) [7]
> А какие-нить серъёзные варианты ещё есть? ;)
Серьёзные варианты могут найтись. Но безгеморройные- врядли. Поэтому я и просил уточнить задачу.
Chuvak (2005-10-02 01:57:00) [17]YurikGL © (02.10.05 1:51) [6]
Можно сначала записать файл, а потом запустить дефрагментатор через shellexecute :)
вопрос был как можно записатьна винчестер файл, а не как избавится от фрагментов....
А какие-нить серъёзные варианты ещё есть? ;)
YurikGL (2005-10-02 01:51:00) [18]Можно сначала записать файл, а потом запустить дефрагментатор через shellexecute :)
Германн (2005-10-02 01:50:00) [19]Ну если интересно, то пожалуйста - Вариант 1: После format буква_диска:первый файл запишется без фрагментации! :)
Chuvak (2005-10-02 01:43:00) [20]Германн © (02.10.05 1:38) [3]
В принципе возможно. НО...
НУ? Интересно же...пусть даже гипотетически...