Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reading a C++ ifstream twice?

Tags:

c++

linux

c++11

How to read a file twice (e.g. like an old two-pass assembler do) using std::ifstream?

I tried the obvious

#include <fstream>
#include <iostream>
#include <string>

int main(int argc, char**argv)
{
  std::string path = argc>1?std::string{argv[1]}:std::string(__FILE__);
  std::ifstream inp{path};
  int num=0;
  std::cout << "first pass" << std::endl;
  do {
    std::string lin;
    std::getline(inp,lin);
    if (inp.eof())
      break;
    num++;
    std::cout << "#" << num << ":" << lin << std::endl;
  } while (!inp.eof());
  inp.seekg(0, inp.beg);
  inp.sync();
  std::cout << "second pass" << std::endl;
  num=0;
  do {
    std::string lin;
    std::getline(inp,lin);
    if (inp.eof())
      break;
    num++;
    std::cout << "##" << num << ":" << lin << std::endl;
  } while (!inp.eof());
  inp.close();
  return 0;
}  

and it does not work (the second loop is looping indefinitely).

FWIW, compiling with GCC 4.9.2 on Linux/x86-64/Debian

precisions

Actually I am trying to parse a file made of lines like ** somename followed (in the next lines) by a JSON object, followed by some empty newlines (and repeatedly again perhaps a ** someothername followed by another JSON object etc...). I need a two-pass algorithm. The first pass is extracting all the names (like somename) and building some "empty" named things. The second pass is filling the named things from the JSON object following them. JSON parsing is done using a recent 1.5 jsoncpp library.

like image 640
Basile Starynkevitch Avatar asked Mar 06 '15 15:03

Basile Starynkevitch


1 Answers

The last call to std::getline upon reaching end-of-stream fails, setting failbit. Since failbit is set, the call to seekg has no effect. You need to clear the stream's status flags before calling seekg (DEMO):

namespace {
void one_pass(std::istream& is) {
  std::string lin;
  for (int num = 0; std::getline(is, lin); ++num) {
    std::cout << '#' << num << ':' << lin << '\n';
  }
}
} // unnamed namespace

int main(int argc, char**argv)
{
  std::ifstream inp{argc > 1 ? argv[1] : __FILE__};

  std::cout << "first pass\n";
  one_pass(inp);

  inp.clear();
  inp.seekg(0);

  std::cout << "\nsecond pass\n";
  one_pass(inp);
}
like image 101
Casey Avatar answered Oct 31 '22 21:10

Casey