Предположим, у меня есть несколько процессов, пишущих большие файлы (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 на диске:
На рисунке показано, что NTFS действительно выделила кластеры для моего файла. Однако для безымянного атрибута DATA StreamDataSize
указано как 0.
Systernals DiskView также подтверждает, что кластеры были выделены
При нажатии клавиши Enter для продолжения теста (и ожидания в течение некоторого времени с момента создания файла на медленном USB-накопителе) поле StreamDataSize
было обновлено
Поскольку я написал 1 байт в конце, NTFS теперь действительно нужно было обнулить все, поэтому SetEndOfFile
действительно помогает с проблемой, о которой я "беспокоюсь".
Я был бы очень признателен, если бы ответы / комментарии также содержали официальную ссылку для подтверждения выдвигаемых требований.
Да, и тестовое приложение выводит это в моем случае:
creating file
file extended, elapsed: 0
writing 'A' at the end
written: 1 bytes, elapsed: 21735
Также для полноты картины приведен пример того, как выглядит атрибут DATA при установке FileAllocationInfo
(обратите внимание, что я создал новый файл для этой картинки)