【问题标题】:Problem with reading file line-by-line逐行读取文件的问题
【发布时间】:2011-02-12 11:47:09
【问题描述】:

我正在尝试完成一个练习来编写一个程序,该程序采用以下命令行参数:输入文件、输出文件和未指定数量的单词。该程序将逐行读取输入文件的内容,为给定的每个单词查找哪些行包含该单词,并将这些行及其行号打印到输出文件。这是我的代码:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

int main(int argc, char* argv[]) {
    if (argc < 4) {
        cerr << "Error #1: not enough arguments provided\n";
        return 1;
    }
    ifstream in(argv[1]);
    if (!in.is_open()) {
        cerr << "Error #2: input file could not be opened\n";
        return 2;
    }
    ofstream out(argv[2]);
    if (!out.is_open()) {
        cerr << "Error #3: output file could not be opened\n";
        return 3;
    }
    ostringstream oss;
    for (int i = 3; i < argc; ++i) {
        int k = 0;
        string temp;
        oss << argv[i] << ":\n\n";
        while (getline(in, temp)) {
            ++k;
            unsigned x = temp.find(argv[i]);
            if (x != string::npos)
                oss << "Line #" << k << ": " << temp << endl;
        }
    }
    string copy = oss.str();
    out << copy;
    in.close();
    out.close();
    return 0;
}

如果我尝试运行它,我会得到给定第一个单词的预测输出,但找不到任何跟在它后面的单词。例如上面的源代码会给出如下输出:

in:

Line #1: #include <iostream>
Line #2: #include <fstream>
Line #3: #include <string>
Line #4: #include <sstream>
Line #5: using namespace std;
Line #7: int main(int argc, char* argv[]) {
Line #12:     ifstream in(argv[1]);
Line #13:     if (!in.is_open()) {
Line #14:         cerr << "Error #2: input file could not be opened\n";
Line #22:     ostringstream oss;
Line #23:     string temp;
Line #24:     for (int i = 3; i < argc; ++i) {
Line #26:         int k = 0;
Line #28:         while (getline(in, temp)) {
Line #30:             unsigned x = temp.find(argv[i]);
Line #31:             if (x != string::npos)
Line #32:                 oss << "Line #" << k << ": " << temp << endl;
Line #35:     string copy = oss.str();
Line #37:     in.close();
out:

也就是说,它会找到给定的第一个单词的所有实例,但不会找到任何后面的实例。我在这里做错了什么?

编辑:我一直在想办法回到文件的开头,但在找不到名为“rewind()”或类似的方法后,我有点放弃了。我在while循环之后添加了in.seekg(0, ios::beg),它仍然给我同样的错误输出。

编辑 2:好的,我终于让步了,并意识到 如果不尝试使用对向量进行某种疯狂的尝试,将无法获得我最初想要的输出,所以我让步了决定以这种形式打印:

found in at line #31:         cerr << "Error #2: input file could not be opened\n";
found out at line #34:     ofstream out(argv[2]);

也就是说,它按顺序打印所有行,并在每一行前面加上找到的特定单词。这是while循环:

ostringstream oss;
string temp;
while(getline(in,temp)) {
    static int count = 1;
    for (int i = 3; i < argc; ++i) {
        unsigned foundWord = temp.find(argv[i]);
        if (foundWord != string::npos)
            oss << "found " << argv[i] << " at line #" << count << ": " << temp << endl;
    }
    ++count;
}

无论如何,感谢您的帮助!练习本身并没有说必须以任何方式格式化输出,因此我认为它已完全完成。

【问题讨论】:

  • +1 用于在main 函数中使用return 而不是exit
  • 请参阅此处 stackoverflow.com/questions/2712076 了解为什么不应该使用 using namespace std 的示例。
  • 哦,我知道命名空间污染很糟糕。我只是习惯于将它用于这些小练习。

标签: c++ file-io fstream


【解决方案1】:

i=3,文件被读取到内部while(getline()) 循环中的EOF。所以在i=4,5,6…,该文件不再可供阅读。

你要么需要在内循环结束后rewind输入文件回到开头,要么切换循环顺序(while(getline(...)) { ... for (int i = 3; ...) { ... } ... }

【讨论】:

    【解决方案2】:

    您正在循环查找要查找的字符串,但您有 getline() 来读取循环中的文件。你真的想要:

    for each input line
       getline
        for each string we are looking for
           is string in line?
    

    【讨论】:

    • 谢谢,这个确实让我知道需要什么。
    【解决方案3】:

    您可以使用函数in.seekg (0, ios::beg); 来回退到文件的开头,然后再重新阅读。

    【讨论】:

      【解决方案4】:

      我的猜测是,每次通过 for 循环时,您都需要将文件指针重置为输入文件的开头。现在,您在循环之外打开它一次,并且没有机制将其重置为后面单词的开头。

      【讨论】:

        【解决方案5】:

        要倒回流,您首先需要调用in.clear() 来取消设置流的状态标志。完成此操作后,您才能调用in.seekg(0, ios::beg) 将获取位置移回开头。

        【讨论】:

          【解决方案6】:

          正如@Neils answer 建议的那样,您的算法存在缺陷。他的伪代码对你来说是一个很好的起点。我建议你接受它并尝试将每个步骤写成更详细的伪代码。重复这样做,直到您觉得伪代码很容易转换为真实代码。我发现这种方法非常有用,对于您以后可能遇到的更复杂的问题也是如此。讽刺地说,在编写代码之前要三思。

          提示您应该考虑将您要查找的单词存储在某种数据结构中,以便您可以反复遍历它们。

          【讨论】:

          • 谢谢,我想我一直在寻找简单的出路,但做对了肯定会更好。尽管不是将单词保留在 argv[3] 中,而且还没有将它们放入数据结构中?
          猜你喜欢
          • 2016-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-21
          • 2012-06-13
          • 2016-11-22
          • 1970-01-01
          相关资源
          最近更新 更多