我使用以下代码在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, 0, 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. */
它不是文件权限或任何东西,它们没问题。
答案 0 :(得分:2)
如果你分配5,1 GB,你最好确保用64位编译代码并在64位Windows版本上运行它。哦,在32位Windows和address space is limited上,内存4 GB with 32 bits code on a 64 bits Windows到最大3 GB。
顺便说一下,ftell()
会返回已签名的long
。您必须检查此处是否存在错误(例如,如果操作系统允许更大的文件大小,则会出现溢出),因此该值不是-1。
修改:
注意with MSVC, long
will currently be即使编译为64位也是32位数。这意味着ftell()
如果文件大小低于2GB(因为符号),将给你一个有意义的结果。
您可以使用非便携式操作系统特定的WinAPI函数GetFileSizeEx()
来获取带符号64位数的大型文件的大小。
malloc()
需要size_t
unsigned 64 bit number。所以在这方面,你是安全的。
另一种方法是使用file mapping。
第二次修改
我查看了您对大小收到的值的编辑,这与我的预期不同。我可以在我的系统上重现错误,并获得一个非空的大小,但它是一个比文件大得多的数字。
查看this CERT security recommendation,似乎fseek()
标准与SEEK_END
组合提供的保证效率不高,并且这种做法非常不安全。
让我们重复一遍:获得大小的最简单方法是在Windows上使用本机操作系统功能,即GetFileSizeEx()
。在64位窗口上有解决方法:使用_fseeki64()
和_ftelli64()
:
...
if (_fseeki64(pFile, 0, SEEK_END)) {
fputs("File seek error", stderr);
return (1);
}
lSize = _ftelli64(pFile); // RETURNS EXACT SIZE
...
这非常有效(最初的问题似乎与返回类型相关联,但返回类型不够大)。但请记住,这是一种解决方法,我担心可能存在其他可能导致CERT报告的漏洞的错误情况。
答案 1 :(得分:1)
数据类型long太小,无法表示文件大小。使用stat()方法(或Windows特定的替代GetFileAttributes)来读取文件大小。