【问题标题】:C++ question regarding how ifstream reads lines and columns关于 ifstream 如何读取行和列的 C++ 问题
【发布时间】:2021-12-30 22:47:06
【问题描述】:

我正在阅读我的一些旧代码,但我意识到我并不确切知道 ifstream 是如何工作的。以下代码应该只是读取一个文件,将其内容保存到一个对象中并创建另一个具有完全相同数据的文件,其写为:

#include <iostream>
#include <fstream>

using namespace std;

class grade {
  public:
    float grade1;
    float grade2;
    float grade3;
};

void read_file(grade data[]){
    ifstream myfile("data.txt");
    int i=0;
    while(myfile >> data[i].grade1){
            myfile >> data[i].grade2 >> data[i].grade3;
            i=i+1; }
    myfile.close();
    myfile.clear();
}

void write_file(grade data[]){
    ofstream myfile("data_out.txt");
    for(int i=0; i<3; i++){
        myfile << data[i].grade1 << "\t" << data[i].grade2 << "\t" << data[i].grade3 << endl;
    }
    myfile.close();
    myfile.clear();
}


int main()
{
    grade data[3];
    read_file(data);
    write_file(data);

    return 0;
}

“data.txt”有:

23.5    10.1    11.6
14.3    8.2     9.3
6.5     6.7     5.3

代码工作得很好,但我不明白 ifstream 如何“知道”在给定时刻它应该在哪一行或哪一列,因为变量i 不用于控制myfile。我假设默认情况下 ifstream 有两个内部变量,一个用于行,另一个用于列,每次识别myfile &gt;&gt; xxx 命令时,列变量都会递增,并且每次循环重复时,行变量都会递增。 是这样的吗?实际上并没有控制代码在给定时刻的行或列,这让我很困惑。 比如说,在这个例子中,我只想读取第二行和第二列的数据。我可以使用像'myfile [1] [1] >> xxx'这样的显式表达式直接访问它吗?我猜getline可以用,但因为它用于字符串我真的不知道。

【问题讨论】:

  • 我不明白 ifstream 如何“知道”在给定时刻它应该是哪一行或哪一列, ifstream 不知道真的知道。 ifstream 一旦碰到一些空格或输入流的结尾,就会停止读取数字。您的代码尝试读取一个数字并检查是否成功,它会尝试再读取 2 个数字,但不关心这两个数字的读取是否成功。读取 3 个数字后,它会递增 i 并重复
  • std::ifstream 不读取任何内容。它是一个数据源。 &gt;&gt; 运算符是您可以用来从 ani 流中读取数据的东西之一。
  • read_filewrite_file 函数中,无需显式关闭文件。析构函数就是这样做的。一旦文件被关闭,就没有理由打电话给clear()

标签: c++ file readfile ifstream


【解决方案1】:

read_file() 中,读取发生在这个循环中:

int i=0;
while(myfile >> data[i].grade1){
        myfile >> data[i].grade2 >> data[i].grade3;
        i=i+1; }

首先,这假设data[] 已经分配了足够数量的元素。奇怪,文件还没读完,怎么知道要提前读多少条记录呢?

那么,这个读取算法假设数据在一个普通的文本文件中,其中数据元素是空格分隔的:

  • myfile &gt;&gt; data[i].grade1 读取新序列的一年级。如果到达文件末尾,结果将被评估为 false,循环将结束。

  • 然后,对于每个第一级读取,循环读取记录的下一个等级:myfile &gt;&gt; data[i].grade2 &gt;&gt; data[i].grade3;

这个逻辑实际上是一个接一个地读取数字。唯一的限制是数字之间有一个或多个空格。因此,流不关心列:它只是要读取的下一个项目。
以下输入文件同样适用:

23.5    
10.1    
11.6
14.3    8.2
9.3 6.5 6.7 5.3

话虽如此,函数结束时不需要关闭和清除流:当函数返回时,它的本地对象将被销毁。这包括流对象,销毁确保一切正常结束。

备注:不完整的记录处理不好:如果一年级存在,但缺少一个,则流将处于错误状态,grade2grade3 元素将保持未初始化状态。

【讨论】:

  • 因此,流不关心列:它只是要读取的下一个项目。 嗯,我现在明白了。按照这个逻辑,似乎实际上不可能读取文件的特定数据,至少不能以这种方式读取。我这么说是因为我习惯使用 Matlab 而不是 C,并且当您使用 Matlab 读取文件时,它会将其内容保存到可以轻松访问的矩阵中。
  • @clkbomber,是的,这是一个不同的世界。在 C++ 中,您需要解析文件。如果你知道你会得到 3 x n 个项目,你可以像以前一样阅读。如果是 m x n,则必须使用动态 2D 数据结构,如果行布局很重要,则需要结合 getline() 读取整行,并进行行解析(例如使用 stringstreams)。
猜你喜欢
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2011-06-09
  • 1970-01-01
  • 2020-08-20
  • 2011-10-26
  • 1970-01-01
相关资源
最近更新 更多