【问题标题】:Read from file: C to C++从文件中读取:C 到 C++
【发布时间】:2014-02-03 05:38:12
【问题描述】:

我一直在尝试读取 C/C++ 中的文件,并且能够为 C 执行此操作,但在使用 C++ 时遇到了一些问题。

背景:我正在尝试读取的文件具有以下结构

i = %3d; j = %3d; a = %3d; b = %3d;
i = %3d; j = %3d; a = %3d; b = %3d;
...

我在C 中工作的代码如下:

#include <stdio.h>
#include <fstream>
#define MAXSIZE 32

int main()
{
    FILE* inputfile = fopen("temp.txt","r");
    int i,j,a,b;

    while (!feof(inputfile))
    {
        fscanf(inputfile,
            "i = %3d; "
            "j = %3d; "
            "a = %3d; "
            "b = %3d;\n",
            &i, &j, &a, &b);

        printf("%3d %3d %3d %3d\n", i,j,a,b);
    }

    fclose(inputfile);
    return 0;
}

当我尝试在C++ 中编写这个程序时,我已经尝试过:

int main()
{
    ifstream inputfile( "temp.txt" ,ios::in);
    int i,j,a,b;

    while (!std::cin.eof())
    {
        inputfile >> "i = " >> i >> "; j = " >> j >> "; a = " >> a >> "; b = " >> b >> ";\n";
        printf("%3d %3d %3d %3d\n", i,j,a,b);
    }
    return 0;
}

但我不太确定应该如何进行格式化
inputfile &gt;&gt; "i = " &gt;&gt; i &gt;&gt; "; j = " &gt;&gt; j &gt;&gt; "; a = " &gt;&gt; a &gt;&gt; "; b = " &gt;&gt; b &gt;&gt; ";\n";
任何帮助将不胜感激。谢谢!

编辑:我面临的问题是倒数第二行的格式不正确。因为我的文件是问题中所述的格式,所以我不能写inputfile &gt;&gt; i &gt;&gt; j &gt;&gt; a &gt;&gt; b;

【问题讨论】:

  • 那么你遇到了什么问题?
  • 您真的需要验证i = j = 等是否存在,还是可以忽略它们并读取数字?
  • @jayeshbhoi 嗨,我已经编辑了问题,希望能明确问题的重点。
  • @JerryCoffin,我试过inputfile &gt;&gt; i &gt;&gt; j &gt;&gt; a &gt;&gt; b;,得到了一个无限循环,输出恒定0 -2 937351794 2007600341。我认为缺少\n 意味着它没有移动到下一行。
  • @BlackAdder:那么倒数第二行的格式吗?在不知道我们真正应该阅读的内容的情况下,很难建议如何阅读数据。

标签: c++ c input io inputstream


【解决方案1】:

只需使用原始代码即可。 各方面都比较好:

  • 它可以工作(除非文件以空行结尾,见下文)。
  • 已经过测试。
  • 它运行得更快。
  • 它在 C 和 C++ 中都完全有效。
  • 它的编译速度更快。

但是,我将提供一项改进:

while (4 == fscanf(inputfile,
        "i = %3d; "
        "j = %3d; "
        "a = %3d; "
        "b = %3d;\n",
        &i, &j, &a, &b))
{
    printf("%3d %3d %3d %3d\n", i,j,a,b);
}
if (!feof(inputfile)) {
    // read failed and the reason wasn't hitting the end of the file
    // maybe you've been keeping track of line numbers and
    // can report where the invalid input was found
}

在尝试读取之前测试 EOF 为时过早。仅在读取到达文件末尾后才会设置 EOF 标志。如果最后一次成功读取实际上找到了'\n',则不会设置 EOF。 iostreams 代码有同样的错误,除了处理中间文本的问题。


Nota Bene:您永远不会注意到用户输入的速度差异,甚至输出到终端的速度差异。但是对于文件 I/O(包括重定向的 stdin 或 stdout),stdio.h 函数比 iostreams 好很多。

【讨论】:

  • 我只是要提到 eof/feof 的事情。好电话。
【解决方案2】:

假设您可以忽略i =j = 等等,而只需要读取数字,一种可能性是创建一个ctype facet,将这些字符分类为空白。使用包含该方面的语言环境为流注入数据,然后读取您的数字:

#include <iostream>
#include <algorithm>
#include <locale>
#include <vector>
#include <sstream>

struct digits_only: std::ctype<char> {
    digits_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
        return &rc[0];
    }
};

class record {
    int i, j, a, b;
public:
    friend std::istream &operator>>(std::istream &is, record &r) {
        return is >> r.i >> r.j >> r.a >> r.b;
    }

    friend std::ostream &operator<<(std::ostream &os, record const &r) {
        return os << r.i << "\t" << r.j << "\t" << r.a << "\t" << r.b;
    }
};

int main() {
    std::stringstream in("i=1 j = 2 a = 10 b = 20\ni = 3 j = 4 a = 30 b = 40");
    std::locale numbers(std::locale(), new digits_only);
    in.imbue(numbers);

    std::vector<record> records{ std::istream_iterator<record>(in),
                                 std::istream_iterator<record>() };

    std::cout << "i\tj\ta\tb\n";
    for (auto const & r : records)
        std::cout << r << "\n";
}

至于这是否比仅使用scanf 更好或更差,我想说这是有问题的。总体上明显更长。 OTOH,上面代码中的很多额外长度是因为我决定将ijab 包装成自己的结构。虽然这只是一个猜测,但我的猜测是您可能无论如何都想这样做。

为了换取一些额外的长度,您可以获得类型安全,并且如果您的代码有多个不同部分需要读取这样的记录,则会更加方便。

与 Ben Voigt 的说法相反,实际测试表明,使用 iostreams 的 I/O 可以与 C 的 stdio 函数完全竞争(在某些情况下更快)。我还没有对这个特殊情况进行足够的测试来确定它是更快、更慢还是差不多,但是我已经做了足够多的其他测试,可以合理肯定地说,C 的 stdio 函数将大大提高远未成定论更快。

底线:继续使用scanf 可能是一个不错的选择,但话又说回来,也可能不是。

【讨论】:

    猜你喜欢
    • 2014-04-02
    • 2012-05-15
    • 2016-06-18
    • 2016-08-02
    • 2020-11-28
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多