【问题标题】:How to write a large binary file to a disk如何将大型二进制文件写入磁盘
【发布时间】:2016-10-28 15:16:17
【问题描述】:

我正在编写一个程序,该程序需要将一个大型二进制文件(大约 12 GiB 或更多)写入磁盘。我创建了一个小测试程序来测试这个功能。虽然为缓冲区分配 RAM 内存不是问题,但我的程序不会将数据写入文件。该文件仍然是空的。即使是 3.72 GiB 文件。

    //size_t bufferSize=1000; //ok
    //size_t bufferSize=100000000; //ok
    size_t bufferSize=500000000; //fails although it is under 4GiB, which shouldn't cause problem anyways
    double mem=double(bufferSize)*double(sizeof(double))/std::pow(1024.,3.);
    cout<<"Total memory used: "<<mem<<" GiB"<<endl;

    double *buffer=new double[bufferSize];
/* //enable if you want to fill the buffer with random data
    printf("\r[%i \%]",0);

    for (size_t i=0;i<(size_t)bufferSize;i++)
    {
        if ((i+1)%100==0) printf("\r[%i %]",(size_t)(100.*double(i+1)/bufferSize));
        buffer[i]=rand() % 100;
    }
*/
    cout<<endl;

     std::ofstream outfile ("largeStuff.bin",std::ofstream::binary);
     outfile.write ((char*)buffer,((size_t)(bufferSize*double(sizeof(double)))));

     outfile.close();

    delete[] buffer;

【问题讨论】:

  • double *buffer=new double[bufferSize]; std::vector 怎么样 - 更安全。
  • 声明streamsize ssz = bufferSize*sizeof(double);并打印出来。也许转换为`streamsize 是一个问题。虽然它对我有用。
  • 老实说,我不知道您在写入调用参数中要使用 double(sizeof(double)) 做什么。同样,对于散布在此代码中的大多数双重结构。如果你的平台上的size_t 不能保持bufferSize * sizeof(double) 的值,double 的中间温度,然后转换回size_t,不会让一切变得更好。您在size_t bufferSize=500000000; //fails... 的评论本身就令人担忧。
  • 神圣多余的 printfs 蝙蝠侠!您每 100 个元素打印一次填充数组的进度 - 这将花费 非常 很长时间。考虑仅打印 100 次进度 - 即,仅当整数百分比发生变化时 - if ((i+1)%(bufferSize/100)==0) 似乎更加理智。另请注意,ofstream.write 的第二个参数应该是 signed - size_t 只是 unsigned int 的别名。
  • 使用size_t 指定大小,而不是double

标签: c++ file c++11


【解决方案1】:

我实际上完全按照您在此处粘贴的代码编译并运行了代码,并且它可以正常工作。它会创建一个 4GB 的文件。

如果您使用的是 FAT32 文件系统,则最大文件大小为 4GB。

否则我建议你检查:

  • 您拥有的可用磁盘空间量。
  • 您的用户帐户是否有任何磁盘使用限制。
  • 您拥有的可用 RAM 量。
  • 是否存在任何运行时错误。
  • @enhzflep 关于打印数量的建议(虽然那是 注释掉)

【讨论】:

    【解决方案2】:

    您似乎希望在写入之前拥有一个包含整个文件内容的缓冲区。

    你做错了,因为:虚拟内存需求基本上是它们需要的两倍。您的进程保留缓冲区,但是当您将该缓冲区写入磁盘时,它会在操作系统的缓冲区中复制。现在,大多数操作系统会注意到您是按顺序写入的,并且可能会很快丢弃它们的缓冲区,但仍然:这是相当浪费的。

    相反,您应该创建一个空文件,将其增长到所需大小,然后将其视图映射到内存中,并对内存中文件的视图进行修改。对于 32 位主机,您的文件大小限制为

    感谢 RAII 的奇妙之处,您无需执行任何特殊操作即可释放映射内存或关闭/完成文件。通过利用 boost,您也可以避免编写特定于平台的代码。

    // https://github.com/KubaO/stackoverflown/tree/master/questions/mmap-boost-40308164
    #include <boost/interprocess/file_mapping.hpp>
    #include <boost/interprocess/mapped_region.hpp>
    #include <boost/filesystem.hpp>
    #include <cassert>
    #include <cstdint>
    #include <fstream>
    
    namespace bip = boost::interprocess;
    
    void fill(const char * fileName, size_t size) {
        using element_type = uint64_t;
        assert(size % sizeof(element_type) == 0);
        std::ofstream().open(fileName); // create an empty file
        boost::filesystem::resize_file(fileName, size);
        auto mapping = bip::file_mapping{fileName, bip::read_write};
        auto mapped_rgn = bip::mapped_region{mapping, bip::read_write};
        const auto mmaped_data = static_cast<element_type*>(mapped_rgn.get_address());
        const auto mmap_bytes = mapped_rgn.get_size();
        const auto mmap_size = mmap_bytes / sizeof(*mmaped_data);
        assert(mmap_bytes == size);
    
        element_type n = 0;
        for (auto p = mmaped_data; p < mmaped_data+mmap_size; ++p)
           *p = n++;
    }
    
    int main() {
       const uint64_t G = 1024ULL*1024ULL*1024ULL;
       fill("tmp.bin", 1*G);
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-01
      • 2010-11-29
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      • 1970-01-01
      相关资源
      最近更新 更多