Zai*_*zvi 2 c++ file-io winapi buffer memory-management
为了制作二进制比较器,我试图使用CreateFileW函数读取两个文件的二进制内容.但是,这会导致整个文件被缓冲到内存中,这对于大型(500MB)文件来说就成了问题.
我已经四处查找了其他函数,它们只是让我只是缓冲部分文件,但是我没有找到任何文档专门说明缓冲区如何为这些函数工作(我有点新,所以也许我我错过了明显的事情.
到目前为止,我似乎找到的最佳匹配是ReadFile.它似乎有一个可定义的缓冲区,但我不完全确定在幕后不会有另外的缓冲区,就像CreateFileW一样.
你们对什么是好的功能有任何意见吗?
不确定CreateFile缓冲是什么意思 - CreateFile不会读取文件的全部内容,此外,你需要调用CreateFile才能调用ReadFile.
ReadFile会做你想做的事情 - 操作系统可以在数据之前做一些读取机会性地缓存数据,但它不会读取整个500 MB的文件.
如果您确实不想进行缓冲,请将FILE_FLAG_NO_BUFFERING传递给CreateFile,并确保您的文件访问是卷扇区大小的倍数.我强烈建议你不要这样做 - 系统文件缓存存在是有原因的并且有助于提高性能.在内存中缓存文件应该不会影响整个系统的内存使用情况 - 在内存压力下,系统文件缓存会缩小.
正如其他人所提到的,您也可以使用内存映射文件.内存映射文件和ReadFile之间的区别主要只是接口 - 最终文件管理器将以类似的方式满足请求,包括一些缓冲.界面看起来更直观一些,但要注意发生的任何错误都会导致需要捕获的异常,否则会导致程序崩溃.
调用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);
此外,如果要读取文件的随机部分,可以在调用ReadFile()之前使用SetFilePointer(),例如读取一千兆字节,从文件开始一兆字节:
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可以自行决定使用可用的系统内存来缓存打开文件的内容,但如果正在运行的程序需要内存,则该进程缓存的数据将被丢弃(毕竟,缓存的数据可以重新读取)如果需要,从磁盘).