1

下面这几行代码的目的是将输入文本文件中的每个单词(单词用换行符分隔)放到一个字符串向量中,然后将每个单词翻过来,看看这个翻出来的单词是否包含在输入文件中的单词列表。

我相信我的二进制搜索功能和 wordTurn 功能工作正常。我对我的代码做了几个简单的测试,我发现使用 while(!myFile.eof()) 循环两次可能是我的代码不起作用的原因。通过不工作,我的意思是我将输出文件(“pairs.txt”)作为一个空文档(它应该是成对的单词列表)。

也就是说,当我在第二个 while(!myFile.eof()) 循环体中放入一些简单的打印代码时,它没有被打印出来,我由此得出结论,这个循环没有到达。这更有可能,因为它是在我注释掉第一个 while(!myFile.eof()) 循环时打印的。我最初将第一个 while 循环放在 else 主体上,但这没有任何区别。

你认为是什么问题?我尝试将这两个循环体组合到第二个循环中,它在输出文件中产生了一些东西,但这不是这段代码应该做的,这在逻辑上是不正确的。

任何建议将不胜感激。

int main(int argc, char* argv[]) {

    vector<string> words;
    ifstream myFile(argv[1]);
    ofstream outputFile("pairs.txt");
    string vocab;
    string s;
    int count;

    while(!myFile.eof()) {                //first while(!myFile.eof()) loop
        getline(myFile, s);
        words.push_back(s);
    }

    if(argc != 2) {
        cout << "Usage: provide the name of one input file after the dictlookupHN executable file." << endl;
        return (1);
    }
    else {
        if(!myFile.is_open()) {
            cerr << "Error: unable to open file " << argv[1] << endl;
            return (1);
        }
        else {
            while(!myFile.eof()) {      //second while(!myFile.eof()) loop
                getline(myFile, vocab);
                string turnedWord = wordTurn(vocab);
                if(binsearch(words, turnedWord) != "") {
                    outputFile << vocab << ":" << turnedWord << endl;
                    count++;
                }
            }
        }

    }
    myFile.close();
    outputFile.close();

    return 0;
}
4

7 回答 7

3

ifstream 类维护流数据的内部偏移量,跟踪它必须从哪里读取,以进行下一个操作。

当此偏移量到达末尾时,它会停止第一个循环,(eof()返回 false)。在再次读取之前,您需要将此内部位置重置回文件的开头。

你可以这样说:

myFile.clear(); // clear stream flags and error state
myFile.seekg(0, ios::beg); // reset read position

在第二个循环之前。

编辑:添加了对clear().

于 2013-03-01T16:26:59.443 回答
2

发生的情况是,当您完成文件的第一次运行时,文件的查找指针位于文件末尾。如果要再次查找文件,则需要在第二次循环myFile.seekg(0, ios::beg);之前重置文件指针。while像这样的东西:

        ...
        else {
                myFile.seekg(0, ios::beg);
                while(!myFile.eof()) {      //second while(!myFile.eof()) loop
        ...

那应该可以解决问题。

于 2013-03-01T16:29:46.430 回答
2

如果您想再次读取文件 [一旦您将整个文件读取到最后],您将需要重置错误/失败位,并从头开始。文件结束是一种永久状态,除非采取措施将其重置。

所以,你需要myFile.clear();并且myFile.seekg(0, ios_base::beg);

虽然我感觉你实际上想在这种特殊情况下打开一个不同的文件,但在这种情况下,我建议关闭当前的文件,并使用不同的变量——它们不是很贵,而且它使代码更清晰 [特别是如果您将其称为合理的东西,例如,vocabFile而不是myFile]

于 2013-03-01T16:30:02.943 回答
2

要再次从文件的开头读取,请使用:

myFile.seekg(0, ios::beg);

但请注意,这不是从文件中读取的好方法:

string vocab;
while(!myFile.eof()) {
    getline(myFile, vocab);
    ...
}

它应该是这样的:

string vocab;
while(getline(myFile, vocab)) {
    if (vocab.empty())
        continue;               // empty line might be read
    ...
}

看一下:为什么我的输入似乎处理超过文件末尾?

于 2013-03-01T16:31:44.430 回答
0

第一个循环到达 EOF,即“读取标记”的位置,因此第二个 EOF 在第二个循环中被读取为第一个。

很简单,尝试在循环之间关闭和打开文件。

更好的主意是使用seekg再次从顶部读取。

于 2013-03-01T16:26:28.860 回答
0

第一个循环到达文件末尾,并且在第二次读取之前您不会重置。您需要在第一个循环之后寻找文件的开头:myFile.seekg (0, ios::beg);将为您执行此操作。

于 2013-03-01T16:28:20.593 回答
0

谢谢大家所有这些好的建议。他们真的帮助我理解了 ifstream 和 eof 是如何工作的。

我的 TA 的建议是使用 for 循环而不是第二个 while(!myFile.eof()) 循环。我可能正在使用此选项,但是当我必须使用 eof 两次时,您的回答会很有帮助。

谢谢!

                    while(!myFile.eof()) { 
                            string s;
                            getline(myFile, s);
                            words.push_back(s);
                    }

                    for(int i=0; i<words.size(); i++) {
                            //LOOP INV: 
                            string vocab = words.at(i);
                            string turnedWord = wordTurn(vocab);
                            if(binsearch(words, turnedWord) == 1 && turnedWord.length() > 3) {
                                    outputFile << vocab << ":" << turnedWord << endl;
                                    count++;
                            }
于 2013-03-01T21:59:19.493 回答