【问题标题】:Reading from input file C++ with istream operator overloading使用 istream 运算符重载从输入文件 C++ 中读取
【发布时间】:2025-12-04 17:45:01
【问题描述】:

我有一个无法更改的输入文件,其中的行略有不同

Supercar   HTT Technologies   10   2
Motorcycle   Honda   40   1
...

为了将值读入我的数据结构,我重载了 >> 运算符,如下所示:

class Vehicles{
private:
string type;  //type of vehicle, i.e. car/motorcycle
string manufacturer;
string manufacturer2ndPart //not a good idea, but this is what I'm using
                           //to get the second part of the manufacturer ("Technologies")
int milesPerGallon;
int numPrevOwn //number of previous owners
public:
...

friend istream &operator >> (istream &is, Vehicles &Vec){
 is >> Vec.type >> Vec.manufacturer >> Vec.milesPerGallon >> Vec.numPrevOwn;
 return is;
     }
};

这在第一行工作得很好,但在输入文件的第二行就崩溃了,因为它试图将“40”读入manufacturer2,而不是milesPerGallon。解决这个问题的最佳方法是什么?我想避免手动读取所有内容,因为这违背了我的运算符重载的目的。

【问题讨论】:

  • 刚刚编辑了这篇文章。第一行被读入并完全正常输出。第二行将“40”读入字符串manufacturer2ndPart,而不是intmilesPerGallon,因此将numPrevOwn 保留为内存中的任何值。
  • 值是如何分开的?
  • 您必须知道输入文件的格式。例如,你怎么知道它不是带有制造商“技术”的“超级跑车 HTT”?应该有一个规则,例如“列至少用 2 个空格分隔”或“一列总是 14 个字符宽。
  • 输入文件值之间用 3 个空格分隔。
  • 您的 >> 运算符实现必须更复杂,我会说它应该调用 get_type()、get_manufacturer() 等,并且您应该在内部处理案例(“类型由多个单词组成”, “制造商由多个词组成”等)

标签: c++ input operator-overloading istream


【解决方案1】:

您的基本问题是流的>> 重载在遇到空格时都会停止,并且您的输入文件包含空格作为数据而不是作为要忽略的内容。因此,您的问题是需要不同数量的字符串,具体取决于行。

一般来说,您最好一次将整行读入一个字符串(例如使用std::getline())。然后在尝试实际提取它们之前检查字符串以计算出它实际包含的字段数。换句话说,不要使用流操作符从文件中读取(或写入)。

稍微改变文件格式也可能值得,这样在字符串字段的开头时就很明显了。例如,像

这样的格式
"Supercar"  "HTT Technologies"   10     2
"Motorcycle" "Honda"    40     1

您仍然需要一次读取一行,但使用" 分隔字符串可以更轻松地识别每个字符串的开头和每个字符串,并处理包含空格(换行符除外)的它们。如果您需要在字符串中包含" 字符,请指定它将以\ 开头,并相应地解析输入。

显然,读取或写入此类文件的任何代码都需要遵守相同的协议。并且读取代码需要处理错误(例如不符合协议的文件)。

【讨论】:

  • 使用 getline 似乎是个好主意,我会将它与 stringstream 结合起来,是吗?我只是对如何实际确定字符串中有多少个“字段”感到有些困惑,因为这似乎与以前的读取过程相同。不幸的是,我无法更改文件格式,但我希望可以:P
  • 你可以使用stringstream。如果您无法更改文件格式,则需要直接检查每一行(例如循环中的每个字符)并计算出在找到整数值之前有多少字符串数据 - 大概在最后。不过,您需要处理诸如“SuperCar6 Company Fumbler#2 10 20”之类的输入——这可以通过向后处理字符串、计算数字和空格来处理,直到到达最后一个字符串数据的末尾。