【问题标题】:how to write data to file larger than 2GB with fstream in c++如何在 C++ 中使用 fstream 将数据写入大于 2GB 的文件
【发布时间】:2015-05-30 02:24:55
【问题描述】:

我搜索了一个 TON 以找到一种方法,使用 fstream 或其他方法将数据写入一个大文件,但没有找到任何答案。

我的问题是,我正在从 Internet 下载数据,然后将数据写入预分配的文件。小于 2GB 的文件似乎一切正常,但是在尝试使用大于 2GB 的预分配文件时,将流指针移动到预分配文件中的特定位置(例如文件的最后位置)时会出错写数据,好像不行,tellp allway return -1。

这是我的写入数据方法,因为写入预分配文件,我没有使用 FILE 或 boost:iosstream。我正在使用带有 .Net 3.5 的 Visual Studio 2008。感谢阅读和帮助我^.^

size_t writeData(void *ptr, size_t size, size_t nmemb, Downloader *objDownloader){
    size_t written;     

    if (objDownloader->_stop == false && objDownloader->mystream.is_open()){

        objDownloader->mystream.seekp(objDownloader->_posSeek, ios::beg);           
        written=size * nmemb;
        objDownloader->mystream.write(static_cast<char*>(ptr), written);

        objDownloader->_posSeek += size*nmemb;
        objDownloader->_downloaded += size*nmemb;

        objDownloader->mystream.seekp(objDownloader->_currentPosition, ios::beg);   
        objDownloader->mystream.write((char*)&objDownloader->_downloaded, sizeof(long long));

        long long  pos = objDownloader->mystream.tellp();           
        cout << "POS TEL: " << pos << endl;

        return size * nmemb;
    }
    else{

        if (objDownloader->mystream.is_open())
            objDownloader->mystream.close();            
        return -1;
    }

}

【问题讨论】:

  • 你是用 32 位还是 64 位构建的?

标签: c++ curl fstream


【解决方案1】:

您的问题与 fstreams 无关,而是与进程内存有关。

下面的代码会生成一个3GB的文件没有问题,使用tellp()显示进度,用seekp()定位到文件末尾:

cout << "size_t is limted to " << numeric_limits<size_t>::max() << " bytes (" << numeric_limits<size_t>::max() /1024/1024<<" MB)"<< endl;
cout << "streamsize is limited to " << numeric_limits<streamsize>::max() << " bytes (" << numeric_limits<streamsize>::max() / 1024 / 1024/1024/104 << " TB)" << endl;

static char mbloc[1024*1024]; 
fill_n(mbloc, sizeof(mbloc), 'A'); 
const size_t blocs = 3*1024; 
ofstream os("test.out"); 
for(int i = 0; i < blocs && os; i++) {
    os.write(mbloc, sizeof(mbloc));
    if(i % 512)
        cout << "tellp() -> " << os.tellp() << "\r";
}
cout << endl;
os.seekp(0, ios::end); 
cout << os.tellp() << " end"<<endl;  
os.close();
cout << "File generation finished"; 

fstreams 实际上被认为非常大。这就是ostream::write() 使用streamsize 类型计数的原因。

tellp() 返回 -1 mens 的事实,因此发生了另一次失败。您可以通过检查 fstream 操作的状态来确定失败的根源,以确定哪些成功,哪些失败。

您在此处的陈述表明您尝试从内存缓冲区中写入所有内容:

     objDownloader->mystream.write(static_cast<char*>(ptr), written);

很遗憾你会在windows下遇到that applies to a 32 bit process的2GB限制问题。这可能会导致写入失败,不是因为 fstream 限制,而是因为底层操作系统的内存限制。

如果您为 64 位编译并在 64 位进程上运行它,则可以将此限制扩展到 8TB,前提是您的计算机上有足够的内存。但是,如果您操作如此庞大的数据,您最好以较小的块在磁盘上写入,而不必将整个文件保存在内存中。

【讨论】:

  • 我的方法写入数据是curl的write_data回调,所以我认为(ptr)的缓冲区永远不会超过2GB,
  • 但是在您的问题中您谈到写入大于 2gb 的文件,并且您的代码显示正在写入缓冲区...
  • 那么,我可以想象 seekp() 有问题。当您有较小的文件时,您的回调是否会被多次调用?还是仅在文件大于 2gb 时才调用多次?
  • 对不起我的英语不好。我使用 libcurl 从互联网下载数据。我的例子是使用 fstream 而不是 FILE 的 curl 的 write_data 回调。预分配文件并将数据填充到较小的 2GB 文件时,一切正常。但是分配更大的文件 3GB ok,所以填充数据失败。无法 seekp() 结束文件 :((
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2018-09-04
  • 2015-12-02
  • 1970-01-01
  • 2017-09-29
相关资源
最近更新 更多