c++ - 读取大量ASCII码并以二进制形式写入

标签 c++ optimization data-processing

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

在处理这些数字之前,我首先将原始文件翻译成二进制格式。这很有用,因为我可以选择是使用 float 还是 double,减小文件大小(double 大约 800 MB,double 大约 400 MB code>float),并在我处理数据后读入适当大小的 block 。

我编写了以下函数来进行 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
}

我想加快 acii_to_binary 的速度,但我似乎无法想出任何办法。我尝试以 8192 字节的 block 读取文件,然后尝试在另一个子例程中处理缓冲区。这看起来非常复杂,因为缓冲区中的最后几个字符可能是空格(在这种情况下一切都很好)或截断的数字(这非常糟糕)——处理可能截断的逻辑似乎不值得。

你会怎么做来加速这个功能?我宁愿依赖标准的 C++(C++11 也行),没有额外的依赖,比如 boost。

谢谢。

编辑:

@大卫施瓦茨:

我尝试按如下方式实现您的建议:

 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;
      }
    }
  }

但是好像没有写数据!我正在努力......

最佳答案

完全做了同样的事情,只是我的字段由制表符'\t'分隔,而且我还必须处理末尾的非数字注释每行和标题行都穿插着数据。

Here是我的实用程序的文档。

我也遇到了速度问题。以下是我为将性能提高 20 倍左右所做的事情:

  • 用内存映射文件替换显式文件读取。一次映射两个 block 。当您在处理一行后位于第二个 block 时,重新映射第二个和第三个 block 。这样,跨越 block 边界的线在内存中仍然是连续的。 (假设没有一行大于一个 block ,您可以增加 block 大小来保证这一点。)
  • 使用 SIMD 指令(例如 _mm_cmpeq_epi8)搜索行尾或其他分隔符。在我的例子中,任何包含 '=' 字符的行都是需要不同处理的元数据行。
  • 使用准系统的数字解析函数(我使用自定义函数来解析 HH:MM:SS 格式的时间,strtodstrtol 非常适合抓取普通数字) .这些比 istream 格式的提取函数快得多。
  • 使用操作系统文件写入 API 而不是标准的 C++ API。

如果您梦想吞吐量达到每秒 300,000 行,那么您应该考虑类似的方法。

当您不使用 C++ 标准流时,您的可执行文件也会缩小。我有 205KB,包括一个图形界面,并且只依赖于 Windows 附带的 DLL(不需要 MSVCRTxx.dll)。再看一遍,我仍在使用 C++ 流进行状态报告。

关于c++ - 读取大量ASCII码并以二进制形式写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14760637/

相关文章:

c++ - std::vector 的性能差是因为没有调用 realloc 的对数次数吗?

c++ - 我应该多久检查一次 fstream 对象是否打开?

python - 减少嵌套循环的计算时间

javascript - 正则表达式在一行中的每 n 个字符和一个完整的单词之前插入 "\r"(基本上是一个自动换行功能)

TYPO3 数据库查询处理器 : Multiple Outputs of same UIDs

C++多UDP socket数据处理

c++ - 带参数列表初始化的模板实参推导

c++ - 为什么我的 operator<< 重载不起作用?

c++ - 如何使用 marshap_cppstd.h 将带有命名空间接口(interface)的 header 包含到 c++/cli 项目中

algorithm - 分组符号最大长度平衡子序列