C++ 读取大量ASCII数字并以二进制形式写入

C++ 读取大量ASCII数字并以二进制形式写入,c++,optimization,data-processing,C++,Optimization,Data Processing,我有大约1.5 Gb的浮点数的数据文件,存储为ASCII文本,用空格分隔,例如,1.2334 2.3456 3.4567等等 在处理这些数字之前,我首先将原始文件转换为二进制格式。这是很有帮助的,因为我可以选择是使用float还是double,减少文件大小(对于double文件大小约为800 MB,对于float文件大小约为400 MB),并在处理数据后读取适当大小的数据块 我编写了以下函数以将ASCII转换为二进制: template<typename RealType=float>

我有大约1.5 Gb的浮点数的数据文件,存储为ASCII文本,用空格分隔,例如,
1.2334 2.3456 3.4567
等等

在处理这些数字之前,我首先将原始文件转换为二进制格式。这是很有帮助的,因为我可以选择是使用
float
还是
double
,减少文件大小(对于
double
文件大小约为800 MB,对于
float
文件大小约为400 MB),并在处理数据后读取适当大小的数据块

我编写了以下函数以将ASCII转换为二进制:

template<typename RealType=float>  
void ascii_to_binary(const std::string& fsrc, const std::string& fdst){    
 RealType value;
 std::fstream src(fsrc.c_str(), std::fstream::in | std::fstream::binary);
 std::fstream dst(fdst.c_str(), std::fstream::out | std::fstream::binary);

 while(src >> value){
  dst.write((char*)&value, sizeof(RealType));
 }
 // RAII closes both files
}
但它似乎没有写入数据!我正在处理它…

使用
RealType
std::vector
将写操作聚合到固定的缓冲区中。您的逻辑应该是这样的:

  • 分配一个带有65536个默认构造项的
    std::vector

  • 在矢量中读取多达65536个条目,替换现有条目

  • 尽可能多地写出你能读懂的条目

  • 如果您恰好读入65536条条目,请转至步骤2

  • 住手,你完了

  • 这将防止您交替读取和写入两个不同的文件,从而显著减少查找活动。它还允许您进行少得多的
    调用,从而减少复制和缓冲逻辑。

    我做了完全相同的事情,只是我的字段由制表符
    '\t'
    分隔,并且我还必须处理每行末尾的非数字注释和散布数据的标题行

    是我的实用程序的文档

    我也有速度问题。以下是我为将性能提高约20倍所做的工作:

    • 用内存映射文件替换显式文件读取。同时绘制两个街区的地图。当处理完一条直线后位于第二个块中时,请与第二个和第三个块重新映射。这样,跨越块边界的线在内存中仍然是连续的。(假设没有一条线大于一个块,您可能可以增加块大小来保证这一点。)
    • 使用SIMD指令,如
      \u mm\u cmpeq\u epi8
      搜索行尾或其他分隔符。在我的例子中,任何包含
      '='
      字符的行都是需要不同处理的元数据行
    • 使用一个基本的数字解析函数(我使用了一个自定义函数来解析HH:MM:SS格式的时间,
      strtod
      strtol
      非常适合抓取普通数字)。这些函数比
      istream
      格式化的提取函数快得多
    • < L>使用OS文件写API代替标准C++ API。< /LI>
    如果你想在300000线/秒范围内实现吞吐量,那么你应该考虑类似的方法。< /P>

    当你不使用C++标准流时,你的可执行文件也会缩小。我有205KB,包括一个图形界面,并且只依赖于Windows附带的dll(不需要MSVCRTxx.dll)。再看一遍,我仍然在用C++流进行状态报告。< /P>你是说把文件大小缩小到800兆字节而不是800 GB?我想你会发现使用经典的C<代码>文件和<代码> fSCANFF()/Cuff>比使用<代码> FStuts有点快。也不要认为你应该在你的输入文件上使用 fSt::Boo2/<代码>它可能对性能没有任何影响,但是正确性会受到影响。@ DanF -是的。谢谢。性能受到你使用的操作系统的极大影响。C++是好的,除了性能外,没有打败OS的API。您可以在读取文件时使用异步文件访问进行处理。注意:您编辑的文章(包括64K写入缓冲区)应使用

    k*sizeof(RealType)
    作为写入大小(以字节为单位),而不是
    buffer.size()
    ,后者是类型
    RealType
    的元素计数。此外,
    dst.flush();dst.close();
    应该在退出时完成。使用
    std::vector
    没有任何好处,因为它是一个固定大小的数组。顺便说一句,只是有理由处理一个文件。结果:
    在55.244秒内完成了2508MB的处理(吞吐量:534426行/秒)
    。如果同时包含源和目标,则为3.87GB的磁盘I/O。
     template<typename RealType=float>  
      void ascii_to_binary(const std::string& fsrc, const std::string& fdst{    
        std::vector<RealType> buffer;
        typedef typename std::vector<RealType>::iterator VectorIterator;
        buffer.reserve(65536);
    
        std::fstream src(fsrc, std::fstream::in | std::fstream::binary);
        std::fstream dst(fdst, std::fstream::out | std::fstream::binary);
    
        while(true){
          size_t k = 0;
          while(k<65536 && src >> buffer[k]) k++;     
          dst.write((char*)&buffer[0], buffer.size());
          if(k<65536){
        break;
          }
        }
      }