【问题标题】:Using C++ ifstream extraction operator>> to read formatted data from a file使用 C++ ifstream 提取运算符>> 从文件中读取格式化数据
【发布时间】:2011-11-18 14:48:42
【问题描述】:

作为我的学习,我正在尝试使用 c++ ifstream 及其运算符>> 使用下面的代码从文本文件中读取数据。文本文件 outdummy.txt 有以下内容:

just dummy
Hello ofstream
555

我的问题是如何将文件中存在的 char 数据读入 char 数组或字符串。如何在下面的代码中使用 ifstream::operator>> 来做到这一点。

#include <iostream>
#include <fstream>

int main()
{
    int a;
    string s;
    char buf[100];
    ifstream in("outdummy.txt",ios_base::in);


    in.operator>>(a); //How to read integer? How to read the string data.??

    cout << a;

    in.close();
    getchar();
    return 0;
}

【问题讨论】:

  • 你的例子是错误的;你甚至没有“正确读取整数”。事实上,那行失败了,a 没有改变,但由于某种原因你已经将它初始化为期望值,所以你自己蒙上了眼睛。
  • @Kerrek 是对的。他是provided 正确且易于使用的解决方案——getlinestring
  • 为什么是char[]?为什么不std::string
  • @jonsca:我的评论主要是修辞。 :)

标签: c++ operators ifstream


【解决方案1】:

如果您想使用格式化输入,您必须提前知道预期的数据并将其读入相应数据类型的变量中。例如,如果您知道数字始终是第五个标记,就像您的示例一样,您可以这样做:

std::string s1, s2, s3, s4;
int n;

std::ifstream in("outdummy.txt");

if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
  std::cout << "We read the number " << n << std::endl;
}

另一方面,如果你知道这个数字总是在第三行,它本身:

std::string line;

std::getline(in, line);  // have line 1
std::getline(in, line);  // have line 2
std::getline(in, line);  // have line 3

std::istringstream iss(line);

if (iss >> n)
{
  std::cout << "We read the number " << n << std::endl;
}

如您所见,要将令牌读取为字符串,您只需将其流式传输到std::string。重要的是要记住格式化的输入运算符逐个标记地工作,并且标记由空格(空格、制表符、换行符)分隔。通常的基本选择是您是完全以令牌(第一个版本)还是逐行(第二个版本)处理文件。对于逐行处理,您首先使用getline 将一行读入字符串,然后使用字符串流对字符串进行标记。


关于验证的一句话:您无法知道格式化提取是否真的会成功,因为这取决于输入数据。因此,您应该始终检查输入操作是否成功,如果没有成功则中止解析,因为在失败的情况下,您的变量将不包含正确的数据,但您无法后来知道了。所以总是这样说:

if (in >> v) { /* ... */ }            // v is some suitable variable
else { /* could not read into v */ }

if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }

后一种结构通常用在while循环中,逐行读取整个文件:

while (std::getline(in, line)) { /* process line */ }

【讨论】:

    【解决方案2】:
    1. ifstream 默认有 ios_base::in。您无需指定。
    2. operator&gt;&gt; 可以直接作为运算符调用:in &gt;&gt; a
    3. 读取字符串是一样的:in &gt;&gt; s,但需要注意的是它是空格分隔的,所以它会自己读取“just”,而不是“dummy”。
    4. 如果您想阅读完整的行,请使用std::getline(in, s)

    【讨论】:

      【解决方案3】:

      由于您选择使用 C 字符串,您可以使用 ifstream 对象的 getline 方法(而不是与 std::strings 一起使用的 std::getline()),这将允许您指定 C-字符串和缓冲区的最大大小。

      根据你所拥有的,并为第二行添加一个额外的缓冲区:

      char buf[100];
      char buf2[100];
      
      in.getline(buf,sizeof(buf));
      in.getline(buf2,sizeof(buf2));
      in >> a;
      

      但是,正如其他发帖人所建议的那样,尝试使用std::string 及其方法,它会让您的生活更轻松。

      【讨论】:

      • Ewwww。 C 数组。魔术数字。 :-(
      • @Kerrek 向合唱团讲道,但我正在尝试根据他的榜样进行调整。
      • 很公平,但我认为如果有人首先建议in.operator&gt;&gt;(a),是时候换衣服了:-)
      • 你是认真的吗? :-) 但请注意,它实际上并没有工作。由于 OP 没有验证返回值,所以错误被掩盖了。
      【解决方案4】:

      您可以读取文件内容并使用Finite State Machine 进行解析。

      例子:

      void Parse(const char* buffer, size_t length);
      size_t GetBufferSize();
      
      size_t bufferSize = GetBufferSize();
      char* buffer = new char[bufferSize];
      
      std::ifstream in("input.txt");
      while(in.getline(buffer, bufferSize)) {
          Parse(buffer, in.gcount());
      }
      

      或者,您可以使用Flex 之类的工具来编写解析器。

      【讨论】:

      • 动态分配一个字符数组?严重地? std::string 有问题吗?
      • 我使用了一个动态分配的 char 数组来与问题中包含的示例保持一致。当然,在生产代码中使用 stringropevector&lt;char&gt; 之类的容器而不是 char 数组会更合适,我应该提到。
      • 问题没有动态分配char数组。
      猜你喜欢
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 2011-12-28
      • 1970-01-01
      • 2023-03-31
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多