在C ++中逐行读取二进制文件

时间:2016-05-07 20:18:22

标签: c++ binary ifstream getline ofstream

我是C ++的初学者,所以我希望你能忍受我。

尝试读取一个文本格式的文件,每个文件都有这样的行(前几行,称为标题行):

@HD VN:1.5  SO:queryname

或者像这样

read.1  4   *   0   0   *   *   0   0   CAACCNNTACCACAGCCCGANGCATTAACAACTTAANNNCNNNTNNANNNNNNNNNNNNTTGAAAAAAAAAAAAAAAAAA    A<.AA##F..<F)<)FF))<#A<7<F.)FA.FAA.)###.###F##)############)FF)A<..A..7A....<F.A    XC:Z:CAACCNNTACCA   RG:Z:A  XQ:i:2

两者都是制表符分隔。

文件非常大,因此是二进制格式。 我想知道是否可以从每行的二进制格式文件中读取,在该行上进行一些处理,然后将其写入二进制格式的输出文件。

我从这段代码开始:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
  string input_file = argv[1];
  string output_file = argv[2];
  string line;
  ifstream istream;
  istream.open(input_file.c_str(),ios::binary|ios::in);
  ofstream ostream;
  ostream.open(output_file.c_str(),ios::binary|ios::out);
  while(getline(istream,line,'\n')){
    if(line.empty()) continue;
    //process line assuming it is read as a string
    ostream<<line<<endl;
  }
  istream.close();
  ostream.close();
}

但是,在{I}尝试将Segmentation fault (core dumped)解析为line string的部分,它与vector崩溃。

有没有办法读取二进制格式并按行拆分,在每条这样的行上进行字符串处理,然后将它们写入二进制输出?

顺便说一下,我在Linux上运行它。

3 个答案:

答案 0 :(得分:8)

  

是否可以逐行读取二进制文件?

原则上,每个文件都是二进制文件,因为这就是计算机的工作方式。现在,说“我试图逐行阅读”显然意味着你将它视为文本文件 - “行”是一个文本概念。

  

文件非常大,因此是二进制格式。

这是一流的废话。大小不会改变文件的格式。

  

如何将每一行作为字符串? ostream<<line<<endl;是否可以将字符串写入二进制文件?

是和否:如果您的文件是而不是文本文件,为什么这些'\n'字符的位置很重要?对于非文本文件,这些只是普通字节,如'a'\0x000xFF。所以基本上,你正在看ingrain wallpaper并尝试在那里发现字母。

但是,通过您对我们正在讨论的文件的说明,它们实际上是仅包含文本的文件。

所以你的问题似乎在于,一行可能会超过std::string中可用的存储空间。这是一种罕见的情况 - 但它似乎可能发生在遗传字符串上。好。

熟悉C ++所具有的非文本文件I / O.基本上,有ifstream.read(),您应该使用它来获取(有限的)字节数,进行处理,写入输出,重复。请注意输入中的换行符,如果您已阅读过,则“倒回”您的文件(fseek)。

另外,我真的很想知道你的线要走多长时间才能打破std::string。我想你可能正在运行一些非常有限的操作系统(32位?)或计算机(非常少的RAM +交换?)。

答案 1 :(得分:2)

如果您的文件结构为行,并且每行以\n终止,则 是文本文件。每个文件都是二进制文件,文本文件只是一种特殊的二进制文件。

因此,鉴于此,您展示的代码可能适用于任何大小的文件。

你应该删除ios:binary,但我不认为在这种情况下会有任何不同。

但是,如果您在“处理”文件的某一行时遇到崩溃,那么这就是最有可能出现错误的地方 - 在您尚未披露的代码中 - 但是!

答案 2 :(得分:1)

看起来你的文件有一些比你预期的其他行结尾。它可能有一个\r,而您希望它有\n。如果是这种情况,那么std::getline会尝试将整个30GB文件读入line std :: string。

我建议您查看文件中的结尾,以便验证上述内容。如果是这种情况,那么您可以使用此SO中的行读取功能:Getting std :: ifstream to handle LF, CR, and CRLF?即使它们的结尾与您的平台不兼容(或者更确切地说是您不期望的结尾),也应该读取行。

另外,使用非二进制文件模式应该没问题。您显示的示例文件行对我来说看起来不是二进制文件。