Segfault在64位Debian上使用ifstream读取大文件

Segfault on reading large file with ifstream on 64 bit Debian

本文关键字:ifstream 读取 文件 64位 Debian Segfault      更新时间:2023-10-16

我正试图在C++中使用ifstream读取一个大文件(~5GB)。由于我使用的是64位操作系统,我认为这应该不是问题。尽管如此,我还是犯了一个错误。使用较小的文件时一切正常,所以我很确定这就是问题所在。

我使用的是g++(4.4.5-8)和libstdc++6(4.4.5-6)。

谢谢。

代码如下:

void load (const std::string &path, int _dim, int skip = 0, int gap = 0) {
    std::ifstream is(path.c_str(), std::ios::binary);
    BOOST_VERIFY(is);
    is.seekg(0, std::ios::end);
    size_t size = is.tellg();
    size -= skip;
    long int line = sizeof(float) * _dim + gap;
    BOOST_VERIFY(size % line == 0);
    long int _N =  size / line;
    reset(_dim, _N);
    is.seekg(skip, std::ios::beg);
    char *off = dims;
    for (long int i = 0; i < N; ++i) {
        is.read(off, sizeof(T) * dim);
        is.seekg(gap, std::ios::cur);
        off += stride;
    }
    BOOST_VERIFY(is);
}

对于i=187664,segfault位于is.read行。T是float,我一次读取dim=1000个float。当segfault发生时,i*步幅远小于大小,所以我不会跑过文件的末尾。

此处分配了dims

void reset (int _dim, int _N)
{
    BOOST_ASSERT((ALIGN % sizeof(T)) == 0);
    dim = _dim;
    N = _N;
    stride = dim * sizeof(T) + ALIGN - 1;
    stride = stride / ALIGN * ALIGN;
    if (dims != NULL) delete[] dims;
    dims = (char *)memalign(ALIGN, N * stride); 
    std::fill(dims, dims + N * stride, 0);
}

我不知道这是否是错误,但这段代码看起来很像C,有很多漏洞。无论如何,尝试更改

void reset (int _dim, int _N)

void reset (size_t dim, size_t _N)
//I would avoid using leading underscores that is usually used to identify elements of the standard library.

当你处理内存中某个东西的大小或索引时,总是使用size_t,它保证能够容纳包括数组在内的对象的最大大小。

我认为你必须使用_ftelli64等…来获得合适的文件大小,并使用long long(或_int64)变量来管理它。但它是C库。我不知道如何在这么大的文件中使用ifstream(实际上>2Go)。你找到路了吗?

PS:在你的情况下,size_t可以,但我不确定32位软件是否可以。我相信64位可以。

int main()
{
    string name="tstFile.bin";
    FILE *inFile,*inFile2;
    fopen_s(&inFile,name.c_str(),"rb"); 
    if (!inFile)
    {
        cout<<"rn***error -> File not foundrn";
        return 0;
    }
    _fseeki64 (inFile,0L,SEEK_END);
    long long fileLength = _ftelli64(inFile); 
    _fseeki64 (inFile,0L,SEEK_SET);
    cout<<"file lg : "<<fileLength<<endl;
    return 1;
}