2011-06-10 122 views
1

我想在读取多个文件之间进行切换。以下是我的代码的简化版本。读取多个文件

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 

代码工作得很好,如果我读文件一次,我认为一切都很酷。但是,如果称为“循环部分”的部分位于循环内部,则行为会变得很奇怪,我开始有一个单独的重复输出。请,有人可以告诉我什么是错的,我该如何解决它?如果你有更好的方法来解决这个问题,请建议。我很感激。

//解决

谢谢大家对你的意见,我很感激。这是我简单做:

而不是原来的

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

我压根儿

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

现在它就像魅力,我可以循环,就像我想:-)。我很感谢你的评论,很高兴认识大哥还有帮助。

+1

时都处于EOF会发生什么? – littleadv 2011-06-10 08:34:38

+1

不应该在分配InFile后检查InFile-> eof()吗? – 2011-06-10 08:43:31

+0

'如果被称为“循环部分”的部分在循环内......例如? – 2011-06-10 08:46:16

回答

4

让我们看看:您发布的代码工作正常,并且您希望我们告诉您 您未发布的代码有什么问题。这相当困难。

不过,您发布的代码可能无法正常工作。 std::istream::eof只能在输入(或某些其他操作)失败后才能可靠地使用;在你发布的代码中,无论如何,几乎 肯定是错误的。

另外:不需要动态分配ifstream;在 事实上,几乎没有什么情况下ifstream 的动态分配是适当的。而且你不检查打开是否成功。

如果您想一个接一个读取两个文件,最简单的方法是使用两个循环,一个接一个(调用处理数据的 的通用函数)。如果由于某种原因不合适,我会 使用自定义流缓冲区,它会在构造函数 中获取文件名列表,并在其到达文件结尾 之前前进到下一个文件,当它到达时仅返回EOF所有 文件的结尾。 (唯一的问题是如果其中一个 open s失败,我会这么做,我经常这样做,它是我的工具包的一部分, ,我使用回调来处理失败。但是,对于一次性使用, 你可以硬编码在任何合适)

作为一个简单的例子:

// 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()) 
    { 
    } 
}; 
+0

@James Kanze:+1。你的答案提供了一个比我的想法更适合OP代码中的逻辑的更好方法。 – 2011-06-10 09:03:18

+0

+1。我喜欢这个主意。 – Nawaz 2011-06-10 09:12:35

+0

您的答案投票。然而,作为一个新手,我对理解代码有困难,并且需要更多时间来研究它。不过,我有几个问题。 1.这些文件有可能被多次使用吗?你能否在代码中加入一些评论,以帮助我理解。我很感激。 – Deadie 2011-06-10 09:17:00

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