【问题标题】:Reading data from a file with wrong count. What's best practice for reading in data?从计数错误的文件中读取数据。读取数据的最佳实践是什么?
【发布时间】:2013-08-12 20:22:19
【问题描述】:

我有四组文本文件,每组都包含不同的单词。

noun.txt 有 7 个单词 Article.txt 有 5 个字 verb.txt 有 6 个单词和 Preposition.txt 有 5 个单词

在下面的代码中,在我的第二个 for 循环中,一个计数数组跟踪我读入了多少单词以及从哪个文件中读取。例如。 count[0] 应该是 5 个世界,但 count[1] 有 8 个单词但应该是 7 个。我回去检查文本文件,我没有弄错,它有 7 个单词。这是 ifstream 行为的问题吗?

我还被告知 eof() 不是好习惯。在准确读取数据方面,行业中的最佳实践是什么?换句话说,除了 !infile.eof() 之外,我还能使用更好的东西吗?

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cctype>
#include <array> // std::array

using namespace std;

const int MAX_WORDS = 100;

class Cwords{
    public:
        std::array<string,4> partsOfSpeech;
};

int main()
{
    Cwords elements[MAX_WORDS];

   int count[4] = {0,0,0,0};

   ifstream infile;

    string file[4] = {"Article.txt",
                      "Noun.txt",
                      "Preposition.txt",
                      "verb.txt"};

    for(int i = 0; i < 4; i++){
        infile.open(file[i]);
        if(!infile.is_open()){
            cout << "ERROR: Unable to open file!\n";
            system("PAUSE");
            exit(1);
        }

        for(int j = 0;!infile.eof();j++){
            infile >> elements[j].partsOfSpeech[i];
            count[i]++;
        }

        infile.close();
    }

    ofstream outfile;
    outfile.open("paper.txt");

    if(!outfile.is_open()){
        cout << "ERROR: Unable to open or create file.\n";
        system("PAUSE");
        exit(1);
    }



    outfile.close();
    system("PAUSE");
    return 0;
}

【问题讨论】:

  • 不要使用.eof()。这里出现的大多数关于读取文件的问题都是滥用.eof()。谁在到处告诉人们使用.eof()?当&gt;&gt; 运算符失败时,任何 C++ 教科书和教程都会告诉你停止阅读;即while (file &gt;&gt; variable) { ... do something ... }
  • @DanielKO 好的,我采纳了你的建议,它有效。我将我的 for 循环转换为 int j = 0; while(infile >> ...) {}.
  • @DanielKO 哦,回答你的问题,很多大学似乎都在推广 .eof()
  • @AmberRoxanna 让你想要求退款,不是吗?

标签: c++ file-io


【解决方案1】:

正确读取数据的简单答案是:总是测试读取后读取操作是否成功。此测试涉及使用eof()(任何在阅读之前教授使用eof() 的书都值得立即烧掉)。

读取文件的主循环应该是这样的:

for (int j = 0; infile >> elements[j].partsOfSpeach[i]; ++j){
    ++count[i];
}

顺便说一句,尽管该语言被称为“C++”而不是“++C”,但除非您确实使用表达式的结果,否则不要使用后自增:在大多数情况下,这无关紧要,但有时确实如此事后增量可能比前增量慢很多。

【讨论】:

  • +1 烧了?? “烧毁”(或者俚语,“火炬”=)怎么样
  • @WhozCraig:也许这是英语和美国之间的区别,但似乎burn 是一个不规则动词,至少,有时。在学校(在德国)我学会了不规则形式......
  • 是的,可能是这样。美国人也使用“烧毁”,尽管“烧毁”它不受欢迎的情况很少见。它使我的好奇心达到了a little research 的位置。直到你提到它,我才真正考虑过。英国和美国之间的差异很有趣。一直在学习新东西。 =)
【解决方案2】:

您是否检查过以确保文本文件末尾没有多余的空格或换行符?您最后一个额外的“单词”可能是由于到达 eof 之前的尾随字符。

【讨论】:

  • 是的,它正在拾取换行符。我以为空格被跳过了?我该如何调整?
  • 出现问题是因为.eof()的使用错误。它会告诉您在 您尝试读取某些内容之后到达文件末尾,但那里什么也没有。它不会像 PASCAL 那样预测未来(也就是说,告诉下一个输入操作是否成功)。
【解决方案3】:

文件末尾可能有一个空行,看起来“空”。我的建议是使用如下代码:

#include <boost/algorithm/string.hpp>
#include <string>

...

    std::string line;
    int cnt = 0;
    while(! infile.eof()) {
        infile >> line;
        boost::algorithm::trim(line);
        if(line.size > 0)
            words[filenr][cnt++] = line;
    }

请注意,我强烈建议有一个“外部”对象,它按列表的类型进行索引(如 Article.txt 为 0,Noun.txt 为 1),而“内部”对象是一个向量,那需要的话。您的实现是相反的,这是次优的,因为您必须在实现中的 partsOfSpeech 向量中携带空槽。另请注意,在您的示例中,为每个文件的字数设置硬上限“100”是非常危险的 - 它可能导致缓冲区溢出!最好将 std::vector 用于实际的单词列表,因为向量很容易自动扩展。

【讨论】:

  • 我很想投反对票:您总是(如:总是)需要在尝试读取之后测试读取是否成功。
  • @DietmarKühl 不熟悉 std 提取运算符的内部结构(尽管我每天都在使用它们),我尊重你的知识。如果infile &gt;&gt; line; 失败line 的内容是否甚至 已定义?如果不是,这不能与定义一起工作,并且可能的副作用是容器中的重复被读取的最后一行。我同意你的看法。
  • @WhozCraig:输入运算符的正常行为是在提取失败时保持参数值不变。尽管标准中的定义没有明确说明,但至少在设置标志 std::ios_base::skipws 时,字符串输入运算符就是这种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-21
  • 2016-03-04
  • 1970-01-01
  • 1970-01-01
  • 2019-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多