如果文件中的空白字符是信息的一部分,那么当使用 >> 操作符读取文件时会出现问题。因为该运算符认为空白字符是分隔符,因此不会读取它们。
例如,来看包含以下信息的文件 mrnphy.txt:
图 1 显示了该信息在文件中记录方式:
在下面的程序的输出中显示了使用 >> 操作符所引起的问题。
//This program shows the behavior of the >> operator on files that contain spaces as part of the information.
// The program reads the contents of the file and transfers those contents to standard output.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
// variables needed to read file
fstream file;
string input;
// Open the file
file.open ("murphy.txt", ios::in);
if (!file)
{
cout << "File open error!" << endl;
return 0;
}
// Read the file and echo to screen
file >> input;
while (!file.fail ())
{
cout << input;
file >> input;
}
// Close the file
file.close ();
return 0;
}
程序屏幕输出:
要解决程序中的问题,其中一种方法是使用读取整行文本的函数。全局函数 getline() 可以用于此目的,它也是字符串库的一部分。其用法如下。
该函数从流 is 中读取一行文本,并将其存储到字符串变量 str 中。该函数具有一个可选的形参 delim,用于标记要读取的行的结尾。分隔字符被从流中移除并丢弃。如果在没有第 3 个形参的情况下调用 getline,则分隔符被认为是行尾字符 '\n'。
第一个参数 is,必须是 istream 类的一个对象。它也可以是 istringstream、ifstream 或 fstream 类中的任何对象(如果传递了 fstream 对象,则必须打开它才能输入)。返回的值是对刚刚读取的输入流的引用。这允许测试返回值以确定调用的成功或失败,如下面的代码段所示:
string str;
if (getline(inputstream, str))
{
//读取一行并存储到str中
cout << str << endl;
}
else
{
//出现错误或到达文件末尾
}
或者,也可以忽略返回值并在调用后的语句中测试流:
string str;
getline(inputstream, str);
if (inputstream)
{
//读取一行并存储到str中
cout << str << endl;
}
else
{
//出现错误或到达文件末尾
}
下面的程序是前面程序的修改版,它使用 getline 函数逐行读取文件,从而保留了单词之间的白色空格:
// This program uses the getline function to read a line of information from the file.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
// Variables needed for file input
fstream nameFile;
string input;
// Open the file
nameFile. open ("murphy.txt" , ios::in);
if (!nameFile)
{
cout << "File open error!" << endl;
return 0;
}
// Read first line of the file
getline(nameFile, input);
while (nameFile)
{
//If successful, print line and read another line
cout << input << endl;
getline(nameFile, input);
}
// Close the file
nameFile.close();
return 0;
}
程序屏幕输出:
由于 getline 函数的第 3 个参数在此程序中被省略了,所以它的默认值是 \n。有时可能想要指定另一个分隔符。例如,来看一个包含多个名称和地址的文件,其内部格式如下:
可以将该文件看成是由 3 个记录组成的。记录是关于单个项目的完整信息集。另外,文件中的记录由 3 个字段组成:
请注意,每个字段以 $ 字符结尾,每个记录以 \n 字符结尾。下面的程序演示了如何使用 getline 函数来检测 $ 字符:
// This file demonstrates the getline function with a user-specified delimiter.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
// Variable needed to read file
string input;
// Open the file.
fstream dataFile ("addresses.txt", ios::in);
if (!dataFile)
{
cout << "Error opening file.";
return 0;
}
// Read lines terminated by '$'' sign and output
getline(dataFile, input, '$');
while (!dataFile.fail())
{
cout << input << endl;
getline(dataFile, input, '$');
}
// Close the file
dataFile.close ();
return 0;
}
程序输出结果:
请注意,标记每个记录结尾的 \n 字符也是输出的一部分。它们会在屏幕上打印出额外的空白行,将记录分开。
另外,使用 $ 之类的可打印字符分隔文件中的信息时,请务必选择一个实际上不会出现在信息本身中的字符。由于任何人的姓名或地址含有 $ 字符都是值得怀疑的,所以在这里它是一个可接受的分隔符。但如果文件中包含美元金额,则应该选择另一个分隔符。