很好地学习iostream 的问题。
让我们从头开始。你可能见过类似的东西:
std::cout << value1 << ',' << value2 << ',' << value3 << '\n';
秘诀是重载运算符<<,可以实现为:
std::ostream& operator << (std::ostream& os, const SomeType& st)
对于许多标准数据类型,该运算符被重载。可以将其链接起来的秘密之一是它返回对给定流的引用。 (请注意,这个函数也可以显式调用)
所以,如果你写:
std::cout << value;
然后,它将值写入std::cout 并返回对给定流std::cout 的引用。如果我们看一下上面的链式调用,那么在 value1 被写入之后,std::cout 被返回。然后要处理的新的 rest 语句将是
std::cout << ',' << value2 << ',' << value3 << '\n';
然后它将输出命令并再次返回std::cout。结果将是:
std::cout << value2 << ',' << value3 << '\n'; // then next
std::cout << ',' << value3 << '\n'; // then next
std::cout << value3 << '\n'; // then next
std::cout << '\n'; // then next
std::cout // then next
您现在可能会问,为什么我列出最后一行很重要。也就是说,因为流的bool 运算符和!(非)运算符都被覆盖了。请阅读here 和here。因此,如果您在条件上下文中使用流,例如在if 或for 或while 中。因此,打开一个流后,你可以简单地写:if (stream),你就知道没有错误。
如果你想循环读取值,那么你可以写
while (filestream >> v1 >> v2 >> v3) { . . .
然后它将按照上述方式进行所有提取,其余语句将为while(filestream)。将调用流的 bool 运算符并检查是否一切正常,或者它们是否失败或 eof(文件结束)。
接下来,了解格式化和非格式化操作的机制很重要。以上都是格式化的。提取器运算符会将流数据转换为您的类型的值。它不会读取任何空格,包括换行符'\n'。在读取下一个值之前,它会先跳过所有的空格,然后读取并转换下一个值,而不是读取尾随的空格。
像std::getline 这样的非格式化输入函数将读取完整的一行,不进行任何转换并从流中消耗最后一个新行'\n'。
这会导致许多理解问题,并且是许多错误的根源。
R.g.如果您有从格式化输入到非格式化输入的转换,则会发生以下情况。 std::cin >> value 中的最后一个格式化输入将读取该值并进行转换。它不会读取换行符。这仍然在流中。并且,对std::getline 的后续调用将一直读取到换行符,它会立即找到它作为第一个字符,作为先前格式化读取的剩余字符,因此什么也不做。
因此,如果存在从格式化输入到未格式化输入的转换,则需要去掉新行(或其他空格)。为此,我们在库中有一个操纵器。它被称为std::ws,并且完全符合我们的要求。请参阅here。它将丢弃输入流中的前导空格。很好。
那么我们现在来看一些示例代码:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
const std::string fileName{ "data.txt" };
int main() {
// Open file and check, if it could be opened
if (std::ifstream inputFileStream{ fileName }; inputFileStream) {
// We want toread 3 values
std::string name{};
int iValue{};
double dValue{};
char comma{};
// Read data from file, convert them to there data type and read until eof
while (std::getline(inputFileStream >> std::ws, name, ',') >> iValue >> comma >> dValue) {
// Show output
std::cout << name << " --> " << iValue << " --> " << dValue << '\n';
}
} // Error message, if file could not be opened
else std::cerr << "\nError:Could not open file '" << fileName << "'\n\n";
return 0;
}
请应用上面的诀窍。首先将调用inputFileStream >> std::ws,它将返回inputFileStream。然后将调用std::getline,这将返回inputFileStream。然后会调用inputFileStream >> Name,返回inputFileStream,以此类推。
我希望,我可以把一些事情说得更清楚。