C++ getline函数用法(无师自通)

如果文件中的空白字符是信息的一部分,那么当使用 >> 操作符读取文件时会出现问题。因为该运算符认为空白字符是分隔符,因此不会读取它们。

例如,来看包含以下信息的文件 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 字符也是输出的一部分。它们会在屏幕上打印出额外的空白行,将记录分开。

另外,使用 $ 之类的可打印字符分隔文件中的信息时,请务必选择一个实际上不会出现在信息本身中的字符。由于任何人的姓名或地址含有 $ 字符都是值得怀疑的,所以在这里它是一个可接受的分隔符。但如果文件中包含美元金额,则应该选择另一个分隔符。