C++ 如何将大型二进制文件写入磁盘

C++ 如何将大型二进制文件写入磁盘,c++,file,c++11,C++,File,C++11,我正在写一个程序,它需要将一个大的二进制文件(大约12Gib或更多)写入磁盘。我创建了一个小测试程序来测试这个功能。虽然为缓冲区分配RAM内存不是问题,但我的程序不会将数据写入文件。文件仍然为空。即使是3.72 GiB文件 //size_t bufferSize=1000; //ok //size_t bufferSize=100000000; //ok size_t bufferSize=500000000; //fails although it is under 4

我正在写一个程序,它需要将一个大的二进制文件(大约12Gib或更多)写入磁盘。我创建了一个小测试程序来测试这个功能。虽然为缓冲区分配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;
//size\u t bufferSize=1000//好啊
//大小\u t bufferSize=100000000//好啊
尺寸=500000000//虽然低于4GiB,但仍会失败,这无论如何都不会导致问题
double mem=double(bufferSize)*double(sizeof(double))/std::pow(1024,3.);

cout事实上,我编译并运行的代码与您粘贴到那里的代码完全相同,并且可以正常工作。它创建一个4GB文件

如果您在FAT32文件系统上,最大文件大小为4GB

否则,我建议您检查:

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

事实上,我编译并运行的代码与您粘贴到那里的代码完全相同,并且可以正常工作。它创建一个4GB文件

如果您在FAT32文件系统上,最大文件大小为4GB

否则,我建议您检查:

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

在写入文件之前,似乎需要一个包含整个文件内容的缓冲区

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


相反,您应该创建一个空文件,将其增长到所需的大小,然后将其视图映射到内存中,并在内存中对文件的视图进行修改。对于32位主机,您的文件大小被限制为,似乎您希望在写入之前有一个包含整个文件内容的缓冲区

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


相反,您应该创建一个空文件,将其增长到所需的大小,然后将其视图映射到内存中,并在内存中对文件的视图进行修改。对于32位主机,文件大小限制为double*buffer=new double[bufferSize];那么std::vector-更安全。declare
streamsize ssz=bufferSize*sizeof(double)并打印它。也许铸造到最大尺寸是个问题。尽管它对我有效。我真的不知道你在写调用参数中尝试使用
double(sizeof(double))
做什么。同样,对于本代码中的大多数双重构造也是如此。如果平台上的
size\u t
无法保持
bufferSize*sizeof(double)
的值,则将中间温度设置为
double
,然后将其转换为
size\u t
,不会让一切变得更好。您在
size\u t bufferSize=500000000中的评论//失败…
本身就令人担忧。神圣的蝙蝠侠!每100个元素打印一次填充数组的进度-这将花费非常长的时间。考虑只打印100次进程——即,只有当整数百分比改变时,<代码> >((i + 1)%(缓冲区大小/ 100)=0)< /C> >看起来更明智。还要注意,ofstream.write的第二个参数应该是有符号的-size\u t仅仅是
无符号int
的别名。使用
size\u t
指定大小,而不是
double
。double*buffer=新的double[bufferSize];那么std::vector-更安全。declare
streamsize ssz=bufferSize*sizeof(double)并打印它。也许铸造到最大尺寸是个问题。尽管它对我有效。我真的不知道你在写调用参数中尝试使用
double(sizeof(double))
做什么。同样,对于本代码中的大多数双重构造也是如此。如果平台上的
size\u t
无法保持
bufferSize*sizeof(double)
的值,则将中间温度设置为
double
,然后将其转换为
size\u t
,不会让一切变得更好。您在
size\u t bufferSize=500000000中的评论//失败…
本身就令人担忧。神圣的蝙蝠侠!每100个元素打印一次填充数组的进度-这将花费非常长的时间。考虑只打印100次进程——即,只有当整数百分比改变时,<代码> >((i + 1)%(缓冲区大小/ 100)=0)< /C> >看起来更明智。还要注意,ofstream.write的第二个参数应该是有符号的-size\u t仅仅是
无符号int
的别名。使用
size\u t
指定大小,而不是
double
// 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);
}