例如,来看包含以下信息的文件 mrnphy.txt:
Jayne Murphy 47 Jones Circle Almond, NC 28702
图 1 显示了该信息在文件中记录方式:
图 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; }
程序屏幕输出:
JayneMurphy47JonesCircleAlmond,NC28702
要解决程序中的问题,其中一种方法是使用读取整行文本的函数。全局函数 getline() 可以用于此目的,它也是字符串库的一部分。其用法如下。
istream& getline (istream& is, string& str, char delim = '/n');
该函数从流 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; }
程序屏幕输出:
Jayne Murphy
47 Jones Circle
Almond, NC 28702
由于 getline 函数的第 3 个参数在此程序中被省略了,所以它的默认值是 /n。有时可能想要指定另一个分隔符。例如,来看一个包含多个名称和地址的文件,其内部格式如下:
addresses. xt的内容
Jayne Murphy$47 Jones Circle$Almond, NC 28702/n$Bobbie Smith$
217 Halifax Drive$Canton, NC 28716/n$Bill Hammet$PO Box 121$ Springfield, NC 28357/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; }
程序输出结果:
Jayne Murphy
47 Jones Circle
Almond, NC 28702
Bobbie Smith
217 Halifax Drive
Canton, NC 28716
Bill Hammet
PO Box 121
Springfield, NC 28357
请注意,标记每个记录结尾的 /n 字符也是输出的一部分。它们会在屏幕上打印出额外的空白行,将记录分开。
另外,使用 $ 之类的可打印字符分隔文件中的信息时,请务必选择一个实际上不会出现在信息本身中的字符。由于任何人的姓名或地址含有 $ 字符都是值得怀疑的,所以在这里它是一个可接受的分隔符。但如果文件中包含美元金额,则应该选择另一个分隔符。
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/22153.html