ifstream:最大的文件大小是多少?

7

我尝试使用 ifstream 读取一个3GB的数据文件,但是它给了我错误的文件大小。而当我读取一个600MB的文件时,它给出了正确的结果。除了错误的文件大小之外,我还无法使用 ifstream 读取整个文件。

以下是我使用的代码:

        std::wstring name;
        name.assign(fileName.begin(), fileName.end());
        __stat64 buf;
        if (_wstat64(name.c_str(), &buf) != 0)
            std::cout << -1; // error, could use errno to find out more

        std::cout << " Windows file size : " << buf.st_size << std::endl;;


        std::ifstream fs(fileName.c_str(), std::ifstream::in | std::ifstream::binary);
        fs.seekg(0, std::ios_base::end);

        std::cout << " ifstream  file size: " << fs.tellg() << std::endl;

3GB文件的输出结果为

 Windows file size : 3147046042
 ifstream  file size: -1147921254

对于600 MB文件的输出结果为

 Windows file size : 678761111
 ifstream  file size: 678761111

万一的情况下,我还测试了5GB文件和300MB文件的情况,

5GB文件的输出结果为:

Windows file size : 5430386900
 ifstream  file size: 1135419604

300MB 文件的输出结果为:

Windows file size : 318763632
 ifstream  file size: 318763632

在我看来,它似乎达到了某个限制。

我正在使用拥有充足内存和磁盘空间的Windows计算机上的Visual Studio 2010测试代码。

我尝试读取一些大型文件。如果ifstream无法读取大型文件,那么使用哪种好的流阅读器?


1
我注意到你直接调用了_wstat64。你是在编译32位二进制文件吗?你尝试过使用64位二进制文件进行ifstream测试吗? - WhozCraig
@WhozCraig:如果文件系统支持,32位代码应该能够处理超过2GB的文件,如果不支持,那就是一个相当糟糕的bug。 - Ben Voigt
@BenVoigt 我同意,我只是好奇在32位实现上stat()(而不是_wstat64())是否表现类似,以及在64位实现上ifstream是否表现不同 - WhozCraig
@WhozCraig:我正在编译的平台是Win32。我还没有尝试64位二进制文件。 - veda
3个回答

7

我认为你想表达的意思是:

std::cout << " ifstream  file size: " << fs.tellg().seekpos() << std::endl;

我手头有一个6GB的文件,至少在这种情况下它能够正常工作。但是我使用的是Visual Studio 2012进行编译。即使你的原始代码也可以在这个环境中正常工作。

所以我怀疑这是VS 2010中std库的一个bug,在VS 2012中得到了修复。无论是pos_type的运算符重载存在问题,还是该类不支持64位处理,目前还不清楚。我需要安装VS 2010来验证,但很可能是这个问题的根源。


根据标准,看起来fpos<char_traits<char>::state_type>tellg()返回的类型)不应该有公共的seekpos()成员。这是一种特定于实现的扩展吗? - Ben Voigt
是的,它解决了问题。现在我得到了正确的结果。 - veda
3
请注意,微软在Visual Studio 15.8中弃用了seekpos()函数,并将其实现更改为始终返回0。 - Brandlingo

4

我稍微修改了你的代码,使其能够编译:

#include <fstream>
#include <iostream>
#include <string>
#include <windows.h>

int main() { 

    std::wstring name(L"whatever.txt");

    __stat64 buf;
    if (_wstat64(name.c_str(), &buf) != 0)
        std::cout << -1; // error, could use errno to find out more

    std::cout << " Windows file size : " << buf.st_size << std::endl;;


    std::ifstream fs(name.c_str(), std::ifstream::in | std::ifstream::binary);
    fs.seekg(0, std::ios_base::end);

    std::cout << " ifstream  file size: " << fs.tellg() << std::endl;

    return 0;
}

我尝试在一个大约3GB的文件上进行操作。使用VS 2012(32位或64位),它产生了以下结果:

 Windows file size : 3581853696
 ifstream  file size: 3581853696

使用32位VS 2008(抱歉,现在没有安装VS 2010的副本),我得到了:

 Windows file size : 3581853696
 ifstream  file size: -713113600

看起来,旧版的VS/VC++在文件大小方面使用了32位有符号数字,因此它们在iostreams中的实际限制可能为2 GB。随着VS 2012的推出,这一点显然已得到纠正。


0

最大文件大小由编译器和操作系统决定。

编译器控制用于访问文件大小的变量的大小。

操作系统确定其支持的最大文件大小。

C++语言不限制文件大小。

示例1:
编译器可以为文件位置变量分配16位,而操作系统可能使用32位指针作为最大文件大小。在这种情况下,编译器是限制因素。

示例2:
编译器可以使用32位文件位置变量,但操作系统使用24位。在这个例子中,操作系统是限制因素。

总之,最大文件大小取决于编译器和操作系统。


我认为你指的是标准库,而不是编译器... 但如果你没有使用适合操作系统的库,那么标准库只能是限制因素。 - Ben Voigt
标准库决定filepos变量的大小还是编译器?我知道size_t的长度由编译器设置。 - Thomas Matthews
标准库并没有指定用于文件位置的类型为 size_tssize_t,通常也不应该这样做,因为文件系统限制远远超过指针限制(即使在 64 位系统上,文件系统也开始使用 128 位长度!)。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接