我正在使用下面的代码在
Windows上的MSVC中打开一个大的(5.1GB)二进制文件.机器有大量的RAM.问题是长度被检索为零.但是,当我将file_path更改为较小的ASCII文件时,代码工作正常.
为什么我不能加载大二进制文件?我喜欢这种方法,因为我想要一个指向文件内容的指针.
- FILE * pFile;
- uint64_t lSize;
- char * buffer;
- size_t result;
- pFile = fopen(file_path,"rb");
- if (pFile == NULL) {
- fputs("File error",stderr); exit(1);
- }
- // obtain file size:
- fseek(pFile,SEEK_END);
- lSize = ftell(pFile); // RETURNS ZERO
- rewind(pFile);
- // allocate memory to contain the whole file:
- buffer = (char*)malloc(sizeof(char)*lSize);
- if (buffer == NULL) {
- fputs("Memory error",stderr); exit(2);
- }
- // copy the file into the buffer:
- result = fread(buffer,1,lSize,pFile); // RETURNS ZERO TOO
- if (result != lSize) { // THIS FAILS
- fputs("Reading error",stderr); exit(3);
- }
- /* the whole file is now loaded in the memory buffer. */
它不是文件的权限或任何东西,他们是罚款.
解决方法
如果您分配了5,1 GB,最好确保您已经编译了64位的代码,并在64位Windows版本上运行. Ohterwhise,内存
address space is limited到最大3 GB,32位Windows和
4 GB with 32 bits code on a 64 bits Windows.
顺便说一下,ftell()
返回一个签名的长.您必须检查这里是否有错误(例如,如果操作系统允许较大的文件大小,则会出现溢出),以使该值不为-1.
编辑:
请注意,with MSVC,long
will currently be即使编译为64位也是32位数.这意味着如果文件大小在2GB以下(因为符号),ftell()会给你一个有意义的结果.
您可以使用非便携式操作系统特定的WinAPI功能GetFileSizeEx()
来获取带有64位数的大型文件的大小.
malloc()需要一个size_t,这是一个unsigned 64 bit number.所以在这方面你是安全的.
另一种方法是使用file mapping.
第二编辑
我看着你对大小收到的价值的编辑,这与我预期的不一样.我可以在我的系统上重现错误,并且具有不为空的大小,但它比文件大得多.
从this CERT security recommendation看,fseek()与SEEK_END相结合的标准提供的担保是不合适的,这使得这是一个非常不安全的做法.
所以让我们重申一下:获取大小的最简单的方法是在Windows上使用本机OS功能,即GetFileSizeEx().在64位窗口中有一个解决方法:使用_fseeki64()和_ftelli64():
- ...
- if (_fseeki64(pFile,SEEK_END)) {
- fputs("File seek error",stderr);
- return (1);
- }
- lSize = _ftelli64(pFile); // RETURNS EXACT SIZE
- ...
这一点很好(初始问题似乎与不够大的返回类型相关联).但是请记住,这是一个解决方法,我担心可能会有其他错误条件可能导致CERT报告的漏洞.