Deadie
Deadie

Reputation: 63

Reading multiple files

I want to alternate between reading multiple files. Below is a simplified version of my code.

ifstream* In_file1 = new ifstream("a.dat",  ios::binary);
ifstream* In_file2 = new ifstream("b..dat",  ios::binary);
ifstream* In_file;
int ID;

In_file = In_file1; 
int ID = 0;

//LOOPING PORTION
if (In_file -> eof())
{
  In_file -> seekg(0, ios_base::beg);
  In_file->close();

  switch (ID)
   {
     case 0:
           In_file = In_file2;  ID = 1; break;
     case 1:
          In_file = In_file1; ID = 0;  break;
   }
}
//some codes
:
:
In_file->read (data, sizeof(double));

//LOOPING PORTION

The code works well if I am reading the files one time and I thought that everything was cool. However, if the part termed 'looping portion' is within a loop, then the behaviour becomes weird and I start having a single repeating output. Please, can someone tell me what is wrong and how I can fix it? If you have a better method of tacking the problem, please suggest. I appreciate it.

//SOLVED

Thank you everybody for your comments, I appreciate it. Here is what I simple did:

Instead of the original

switch (ID)
{
  case 0:
   In_file = In_file2;  ID = 1; break;
   case 1:
   In_file = In_file1; ID = 0;  break;
}

I simply did

switch (ID)
{
  case 0:
   In_file = new ifstream("a.dat",  ios::binary);  ID = 1; break;
  case 1:
  In_file = new ifstream("b.dat",  ios::binary);  ID = 0;  break;
}

Now it works like charm and I can loop as much as I want:-). I appreciate your comments, great to know big brother still helps.

Upvotes: 1

Views: 4273

Answers (2)

Omer
Omer

Reputation: 1

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

#define NO_OF_FILES 2

int main () 
{
  std::ifstream in;
  std::string line;
  std::string files[NO_OF_FILES] = 
  {
    "file1.txt", 
    "file2.txt",
  };
  // start our engine!
  for (int i = 0; i < NO_OF_FILES; i++)
  {
    in.open(files[i].c_str(), std::fstream::in);
    if (in.is_open())
    {
      std::cout << "reading... " << files[i] << endl;
      while (in.good())
      {
        getline(in, line);
        std::cout << line << std::endl;
      }
      in.close();
      std::cout << "SUCCESS" << std::endl;
    }
    else
      std::cout << "Error: unable to open " + files[i] << std::endl;
  }

  return 0;
}

Upvotes: 0

James Kanze
James Kanze

Reputation: 154007

Let's see: the code you posted works fine, and you want us to tell you what's wrong with the code you didn't post. That's rather difficult.

Still, the code you posted probably doesn't work correctly either. std::istream::eof can only be used reliably after an input (or some other operation) has failed; in the code you've posted, it will almost certainly be false, regardless.

In addition: there's no need to dynamically allocate ifstream; in fact, there are almost no cases where dynamic allocation of ifstream is appropriate. And you don't check that the opens have succeeded.

If you want to read two files, one after the other, the simplest way is to use two loops, one after the other (calling a common function for processing the data). If for some reason that's not appropriate, I'd use a custom streambuf, which takes a list of filenames in the constructor, and advances to the next whenever it reaches end of file on one, only returning EOF when it has reached the end of all of the files. (The only complication in doing this is what to do if one of the opens fails. I do this often enough that it's part of my tool kit, and I use a callback to handle failure. For a one time use, however, you can just hard code in whatever is appropriate.)

As a quick example:

//  We define our own streambuf, deriving from std::streambuf
//  (All istream and ostream delegate to a streambuf for the
//  actual data transfer; we'll use an instance of this to
//  initialize the istream we're going to read from.)
class MultiFileInputStreambuf : public std::streambuf
{
    //  The list of files we will process
    std::vector<std::string> m_filenames;
    //  And our current position in the list (actually
    //  one past the current position, since we increment
    //  it when we open the file).
    std::vector<std::string>::const_iterator m_current;

    //  Rather than create a new filebuf for each file, we'll
    //  reuse this one, closing any previously open file, and
    //  opening a new file, as needed.
    std::filebuf m_streambuf;

protected:
    //  This is part of the protocol for streambuf.  The base
    //  class will call this function anytime it needs to
    //  get a character, and there aren't any in the buffer.
    //  This function can set up a buffer, if it wants, but
    //  in this case, the buffering is handled by the filebuf,
    //  so it's likely not worth the bother.  (But this depends
    //  on the cost of virtual functions---without a buffer,
    //  each character read will require a virtual function call
    //  to get here.
    //
    //  The protocol is to return the next character, or EOF if
    //  there isn't one.
    virtual int underflow()
    {
        //  Get one character from the current streambuf.
        int result = m_streambuf.sgetc();
        //  As long as 1) the current streambuf is at end of file,
        //  and 2) there are more files to read, open the next file
        //  and try to get a character from it.
        while ( result == EOF && m_current != m_filenames.eof() ) {
            m_streambuf.close();
            m_streambuf.open( m_current->c_str(), std::ios::in );
            if ( !m_streambuf.is_open() )
                //  Error handling here...
            ++ m_current;
            result = m_streambuf.sgetc();
        }
        //  We've either gotten a character from the (now) current
        //  streambuf, or there are no more files, and we'll return
        //  the EOF from our last attempt at reading.
        return result;
    }

public:
    //  Use a template and two iterators to initialize the list
    //  of files from any STL sequence whose elements can be
    //  implicitly converted to std::string.
    template<typename ForwardIterator>
    MultiFileInputStreambuf(ForwardIterator begin, ForwardIterator end)
        : m_filenames(begin, end)
        , m_current(m_filenames.begin())
    {
    }
};

Upvotes: 5

Related Questions