【问题标题】:Using fscanf to read from tabbed file with ints and floats in C++在 C++ 中使用 fscanf 从带有整数和浮点数的选项卡式文件中读取
【发布时间】:2016-06-14 14:56:35
【问题描述】:

我在 StackOverflow 和其他网站上找了一天左右,但找不到解决问题的方法。有一些是相似的,但我似乎无法让它们工作。

我有一个制表符分隔的 .txt 文件。一行包含一个标题,之后的 500 行依次包含一个整数、一个整数、一个浮点数、一个整数和一个整数。我有一个函数应该从每一行读取第一个和第三个值(第一个整数和浮点数)。它跳过第一行。这是在一个 do-while 循环中,因为我需要能够处理不同长度的文件。但是,它陷入了循环。我将其设置为输出平均值,但它只会永远输出零。

void HISTS::readMeans(int rnum) {
    int r;
    char skip[500];
    int index = 0; int area = 0; double mean = 0; int min = 0; int max = 0;

    FILE *datafile = fopen(fileName,"r");
    if(datafile == NULL) cout << "No such file!\n";
    else {
            //ignore the first line of the file
            r = fscanf(datafile,"%s\n",skip);
            cout << skip << endl; //just to check

            //this is the problematic code
            do {
                    r = fscanf(datafile,"%d\t%d\t%f\t%d\t%d\n",&index,&area,&mean,&min,&max);
                    cout << mean << " ";
            } while(feof(datafile) != 1)
    }
    fclose(datafile);
}

这是我正在尝试读取的格式的示例数据文件:

        Area        Mean        Min        Max
1       262144      202.448     160        687
2       262144      201.586     155        646
3       262144      201.803     156        771

谢谢!

编辑:我说我需要读取第一个和第三个值,我知道我正在读取所有这些值。最终我需要存储第一个和第三个值,但为了简洁起见,我删掉了那部分。并不是说这个评论很简短。

【问题讨论】:

  • 您的流中的某些行是否可能与此格式不匹配?在这种情况下, fscanf() 返回,使流保持原样,这意味着它永远不会到达 EOF。
  • 如果是这样的话,我想我会非常惊讶。某些东西可以看起来像一个数字,但实际上是其他字符吗?它只是一个 .txt 文件,但它是由另一个程序(ImageJ)生成的,所以我想它是远程可能的。有什么好的方法来告诉?
  • @Gwen while(feof(datafile) != 1) 你能把;(分号)放在后面试试吗??
  • 我试过了;感谢您发现错字。还是不行。
  • @Gwen 很高兴为您提供帮助。

标签: c++


【解决方案1】:

你应该使用 C++ 风格,

#include <iostream>
#include <fstream>

int main() {
  std::ifstream inf("file.txt");
  if (!inf) { exit(1); }
  int idx, area, min, max;
  double mean;

  while (inf >> idx >> area >> mean >> min >> max) {
    if (inf.eof()) break;
    std::cout << idx << " " << area << " " << mean << " " << min << " " << max << std::endl;
  }
  return 0;
}

它是:

1) 易于阅读。

2) 更少的代码,因此出错的机会更少。

3) 正确处理EOF

虽然我已经离开了第一行的处理,但这取决于你。

【讨论】:

  • 我想过这样做,但我使用的是 ROOT C++ 解释器,而且我有一个旧版本,我无法很好地使用这种格式。我认为询问阅读文件比询问 ROOT 更幸运,因为似乎没有人(甚至使用它的人)对此了解很多。不过,如果我无法解决其他问题,我可能会回到那个状态。
  • @Gwen :) 祝你好运!
  • 好的,所以我最终还是这样做了。感谢您的帮助!
  • 嗯,if (inf.eof()) break; 是个坏主意。在最好的情况下没用,在最坏的情况下很危险,好像文件的最后一行没有被换行符终止(可能会发生),该行将被跳过。 mean 也应该是双精度或浮点数...
  • @Bob__ 只是没用,不危险。与 getline 不同的 Stream 不会吞噬换行符。是的,mean 应该是双倍的。
【解决方案2】:

fscanf 返回读取的参数数量。因此,如果它返回小于 5,您应该退出循环。

【讨论】:

  • 我检查过了,它确实退出了循环,但这仍然不能真正解决问题——它只是立即退出循环,没有读取任何内容。
  • 这个时skip的内容是什么? fscanf() 是否在第一次读取时贪婪地获取整个文件?
  • skip 里面只有“Area”。我认为 %s 只是读取到第一个空格。这很好,因为我不在乎保存第一行的信息。这会导致问题吗?也许 fscanf() 尝试读取的下一件事是“区域”之后的空格?
  • @Gwen 使用cat -vet &lt;file_name&gt;验证文件格式。
  • 如果'skip'只有“Area”,那么你随后的 fscanf() 读取将是不正确的,因为你将从“\tMean...”而不是输入的第一行开始.而不是第一个 fscanf() 吞下第一行,尝试使用 getline(),它将占用整个第一行。
【解决方案3】:

OP 最终使用了operator&gt;&gt;,这是在 C++ 中执行此操作的正确方法。但是,对于感兴趣的 C 语言读者,发布的代码中存在一些问题:

  • mean 被声明为 double,但读取时使用了错误的格式说明符 %f 而不是 %lf
  • 第一行没有被完全读取,只有第一个标记Area

实现所需任务的可能方法如下:

r = fscanf(datafile,"%[^\n]\n",skip);
//                    ^^^^^ read till newline

while ( (r = fscanf(datafile,"%d%d%lf%d%d",&index,&area,&mean,&min,&max)) == 5 ) {
    //                             ^^ correct format specifier for double
    // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 2014-03-13
    • 2015-05-14
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    相关资源
    最近更新 更多