Предположим, у меня есть несколько процессов, пишущих большие файлы (20 ГБ +). Каждый процесс записывает свой собственный файл и предполагает, что процесс записывает x mb за раз, затем выполняет некоторую обработку и снова записывает x mb и т. Д.
В результате этого шаблона записи файлы будут сильно фрагментированы, поскольку блоки файлов последовательно размещаются на диске.
Конечно, легко обойти эту проблему, используя SetEndOfFile
, чтобы «предварительно выделить» файл при его открытии, а затем установить правильный размер перед его закрытием. Но теперь приложение, обращающееся к этим файлам удаленно, которое может анализировать эти файлы в процессе, очевидно, видит нули в конце файла и занимает намного больше времени для анализа файла.
У меня нет контроля над этим приложением для чтения, поэтому я не могу оптимизировать его для учета нулей в конце.
Еще одним грязным решением было бы чаще запускать дефрагментацию, запускать утилиту contig Systernal или даже реализовывать собственный «дефрагментатор», который обрабатывал мои файлы и объединял их блоки.
Другим более радикальным решением было бы внедрение драйвера минифильтра, который сообщал бы о «поддельном» размере файла.
Но очевидно, что оба решения, перечисленные выше, далеки от оптимальных. Поэтому я хотел бы знать, есть ли способ предоставить подсказку о размере файла для файловой системы, чтобы она «резервировала» последовательное пространство на диске, но все же сообщала приложениям правильный размер файла?
В противном случае, очевидно, что запись больших кусков за раз, очевидно, помогает с фрагментацией, но все еще не решает проблему.
EDIT:
Поскольку полезность SetEndOfFile
в моем случае, кажется, оспаривается, я сделал небольшой тест:
LARGE_INTEGER size;
LARGE_INTEGER a;
char buf='A';
DWORD written=0;
DWORD tstart;
std::cout << "creating file\n";
tstart = GetTickCount();
HANDLE f = CreateFileA("e:\\test.dat", GENERIC_ALL, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
size.QuadPart = 100000000LL;
SetFilePointerEx(f, size, &a, FILE_BEGIN);
SetEndOfFile(f);
printf("file extended, elapsed: %d\n",GetTickCount()-tstart);
getchar();
printf("writing 'A' at the end\n");
tstart = GetTickCount();
SetFilePointer(f, -1, NULL, FILE_END);
WriteFile(f, &buf,1,&written,NULL);
printf("written: %d bytes, elapsed: %d\n",written,GetTickCount()-tstart);
Когда приложение выполняется и ожидает нажатия клавиши после SetEndOfFile, я проверил структуры NTFS на диске:
![before](https://i.stack.imgur.com/OjF3H.png)
На рисунке показано, что NTFS действительно выделила кластеры для моего файла. Однако для безымянного атрибута DATA StreamDataSize
указано как 0.
Systernals DiskView также подтверждает, что кластеры были выделены
![DickView](https://i.stack.imgur.com/Jz99Y.png)
При нажатии клавиши Enter для продолжения теста (и ожидания в течение некоторого времени с момента создания файла на медленном USB-накопителе) поле StreamDataSize
было обновлено
![enter image description here](https://i.stack.imgur.com/mPj5P.png)
Поскольку я написал 1 байт в конце, NTFS теперь действительно нужно было обнулить все, поэтому SetEndOfFile
действительно помогает с проблемой, о которой я "беспокоюсь".
Я был бы очень признателен, если бы ответы / комментарии также содержали официальную ссылку для подтверждения выдвигаемых требований.
Да, и тестовое приложение выводит это в моем случае:
creating file
file extended, elapsed: 0
writing 'A' at the end
written: 1 bytes, elapsed: 21735
Также для полноты картины приведен пример того, как выглядит атрибут DATA при установке FileAllocationInfo
(обратите внимание, что я создал новый файл для этой картинки)
![enter image description here](https://i.stack.imgur.com/5HbRw.png)