Резервное дисковое пространство перед записью файла для эффективности

Я заметил огромное снижение производительности в одном из моих проектов, когда регистрация включена впервые. Но когда предел файла журнала достигнут, и программа снова начинает запись в начало файла, скорость регистрации намного выше (примерно на 50% быстрее). Нормально установить размер файла журнала в сотни МБ.

Большинство менеджеров загрузки выделяют фиктивный файл необходимого размера перед началом загрузки файла. Это делает написание более эффективным, потому что весь блок выделяется сразу.

Каков наилучший способ эффективно зарезервировать дисковое пространство при фиксированном размере, когда моя программа запускается впервые?

4 ответа

Решение
void ReserveSpace(LONG spaceLow, LONG spaceHigh, HANDLE hFile)
{
    DWORD err = ::SetFilePointer(hFile, spaceLow, &spaceHigh, FILE_BEGIN);

    if (err == INVALID_SET_FILE_POINTER) {
        err = GetLastError();
        // handle error
    }
    if (!::SetEndOfFile(hFile)) {
        err = GetLastError();
        // handle error
    }
    err = ::SetFilePointer(hFile, 0, 0, FILE_BEGIN); // reset
}

Если вы используете C++ 17, вам следует сделать это с помощьюstd::filesystem::resize_file

Ссылка

Изменяет размер обычного файла с именем p, как если бы он был усечен POSIX: если размер файла ранее был больше, чем new_size, остаток файла отбрасывается. Если файл ранее был меньше, чем new_size, размер файла увеличивается, и новая область выглядит как заполненная нулями.

#include <iostream>
#include <iomanip>
#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;

int main()
{
    fs::path p = fs::current_path() / "example.bin"; 
    std::ofstream(p).put('a');
    fs::resize_file(p, 1024*1024*1024); // resize to 1 G
}

WRAR это правильно. Откройте новый файл, используя вашу любимую библиотеку, затем найдите предпоследний байт и запишите там 0. Это должно выделить все необходимое дисковое пространство.

Если вы используете C#, вы можете позвонить SetLength на FileStream чтобы мгновенно установить начальный размер файла.

например

using (var fileStream = File.Open(@"file.txt", FileMode.Create, FileAccess.Write, FileShare.Read))
{
    fileStream.SetLength(1024 * 1024 * 1024); // Reserve 1 GB
}

Вы можете использовать функцию SetFileValidData, чтобы увеличить логическую длину файла без необходимости записывать все эти данные на диск. Тем не менее, поскольку он может позволять читать данные на диске, к которым у вас нет других прав доступа, требуется SE_MANAGE_VOLUME_NAME привилегия использовать. Внимательно прочитайте раздел "Замечания" в документации.

Также реализация SetFileValidData зависит от драйвера fs. NTFS поддерживает его и FAT только начиная с Win7.

Вот простая функция, которая будет работать для файлов любого размера:

void SetFileSize(HANDLE hFile, LARGE_INTEGER size)
{
    SetFilePointer(hFile, size, NULL, FILE_BEGIN);
    SetEndOfFile(hFile);
}
Другие вопросы по тегам