Чтение бинарных файлов без буферизации всего файла в памяти в C ++ - PullRequest
2 голосов
/ 19 августа 2009

Чтобы сделать двоичный компаратор, я пытаюсь прочитать двоичное содержимое двух файлов, используя функцию CreateFileW. Однако это приводит к тому, что весь файл буферизуется в памяти, и это становится проблемой для больших (500 МБ) файлов.

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

Пока что лучшее совпадение, которое я нашел, это ReadFile. Кажется, он имеет определяемый буфер, но я не совсем уверен, что за кулисами не будет реализован еще один буфер, как в CreateFileW.

Ребята, есть ли у вас какие-либо сведения о том, какую функцию лучше использовать?

Ответы [ 4 ]

7 голосов
/ 19 августа 2009

Вы можете использовать файлы с отображением памяти для этого. откройте с помощью createFile, используйте createFileMapping, затем MapViewOfFile, чтобы получить указатель на данные.

5 голосов
/ 19 августа 2009

Вызов CreateFile () сам по себе не буферизует и не читает содержимое целевого файла. После вызова CreateFile () необходимо вызвать ReadFile () , чтобы получить любые части файла, которые вы хотите, например, чтобы прочитать первый килобайт файла:

DWORD cbRead;
BYTE buffer[1024];
HANDLE hFile = ::CreateFile(filename,
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
::ReadFile(hFile, sizeof(buffer), &cbRead, NULL);
::CloseHandle(hFile);

Кроме того, если вы хотите прочитать случайную часть файла, вы можете использовать SetFilePointer () перед вызовом ReadFile (), например, чтобы прочитать один килобайт, начиная с одного мегабайта, в файл:

DWORD cbRead;
BYTE buffer[1024];
HANDLE hFile = ::CreateFile(filename,
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
::SetFilePointer(hFile, 1024 * 1024, NULL, FILE_BEGIN);
::ReadFile(hFile, sizeof(buffer), &cbRead, NULL);
::CloseHandle(hFile);

Разумеется, вы можете вызывать SetFilePointer () и ReadFile () столько раз, сколько пожелаете, пока файл открыт. Вызов ReadFile () неявно устанавливает указатель файла на байт, непосредственно следующий за последним байтом, прочитанным ReadFile ().

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

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

5 голосов
/ 19 августа 2009

Не уверен, что вы подразумеваете под буферизацией CreateFile - CreateFile не будет читать все содержимое файла, и, кроме того, вам нужно вызвать CreateFile, прежде чем вы сможете вызывать ReadFile.

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

Если вы действительно не хотите буферизовать, передайте FILE_FLAG_NO_BUFFERING в CreateFile и убедитесь, что ваши обращения к файлам кратны размеру сектора тома. Я настоятельно рекомендую вам не делать этого - системный файловый кеш существует по причине и помогает с производительностью. Кэширование файлов в памяти не должно влиять на общее использование памяти системой - под давлением памяти кэш системного файла будет сокращаться.

Как уже упоминалось, вы также можете использовать файлы с отображением в памяти. Разница между файлами, отображаемыми в память, и ReadFile заключается главным образом в интерфейсе - в конечном итоге файловый менеджер будет удовлетворять запросы аналогичным образом, включая некоторую буферизацию. Интерфейс выглядит немного более интуитивно понятным, но имейте в виду, что любые возникающие ошибки приведут к исключению, которое необходимо будет отловить, иначе это приведет к сбою вашей программы.

1 голос
/ 19 августа 2009

Я полагаю, что вы хотите MapViewOfFile .

...