文件输入输出
文本I/O和文本文件
使用cin进行输入时,程序将输入视为一系列的字节,其中每个字节都被解释为字符编码。不管目标数据类型是什么,输入一开始都是字符数据——文本数据。然后,cin对象负责将文本转换为其他类型。
假设有如下示例输入行:
38.5 19.2
来看一下使用不同数据类型的变量来存储时,cin是如何处理输入行的。
char类型:
char ch;
cin >> ch;
输入行中的第一个字符被赋给ch。在这里,第一个字符是数字3,其字符编码(二进制)被存储在变量ch中。输入和目标变量都是字符,因此不需要进行转换。注意这里存储的是字符3的编码。执行上述输入语句后,输入队列中的下一个字符为字符8,下一个输入操作将对其进行处理。
int类型:
int n;
cin >> n;
在这种情况下,cin将不断读取,直到遇到非数字字符。也就是说,它将读取3和8,这样句点将成为输入队列中的下一个字符。cin通过计算发现,这两个字符对应数值38,因此将38的二进制字符复制到变量n中。
double类型:
double x;
cin >> x;
在这种情况下,cin将不断读取,直到遇到第一个不属于浮点数的字符。也就是说,cin读取3、8、句点和5,使得空格成为输入队列中的下一个字符。cin通过计算发现,这四个字符对应于数值38.5,因此将38.5的二进制编码(浮点格式)复制到变量x中。
char数组:
char word[50];
cin >> word;
在这种情况下,cin将不断读取,直到遇到空白字符。也就是说,它读取3、8、句点和5,使得空格成为输入队列中下一个字符。然后,cin将这4个字符的编码存储到数组word中,并在末尾加上一个空字符。这里不需要进行任何转换。
最后,来看一下另一种使用char数组来存储输入的情况:
char word[50];
cin.getline(word,50);
在这种情况下,cin将不断读取,直到遇到换行符(示例输入行少于50个字符)。所有字符都被存储到数组word中,并在末尾加上一个空字符。换行符被丢弃,输入队列中的下一个字符是下一行中的第一个字符。这里不需要进行任何转换。
本文讨论的文件I/O仅适用于文本文件。
写入到文本文件中
对于文件输入,C++使用类似于cout的东西。使用cout要注意以下几点:
- 必须包含头文件iostream
- 头文件iostream定义了一个用于处理输出的ostream类
- 头文件iostream声明了一个名为cout的ostream变量(对象)
- 必须指明名称空间std
可以结合使用cout和运算符<<来显示各种类型的数据
文件输出与此极其类似:
- 必须包含头文件fstream
- 头文件fstream定义了一个用于处理输出的ofstream类
- 需要声明一个或多个ofstream类(对象),并以自己喜欢的方式对其进行命名,条件是遵守常用的命名规则
- 必须指明名称空间std
- 需要将ofstream对象与文件关联起来。为此,方法之一是使用open()方法
- 使用完文件后,应使用方法close()将其关闭
可结合使用ofstream对象和运算符<<来输出各种类型的数据
注意:虽然头文件iostream提供了一个预先定义好的名为cout的ostream对象,但我们必须声明自己的ofstream对象,为其命名,并将其同文件关联起来:
声明对象:
ofstream outFile;
ofstream fout;
将这种对象与特定的文件关联起来:
outFile.open("fish.txt"); //outFile用于写入fish.txt
char filename[50];
cin >> filename; //用户指定一个名字
fout.open(filename); //fout用于读取特定文件
注意,方法open()接受一个C-风格字符串作为参数,这可以是一个字面字符串,也可以是存储在数组中的字符串。
下面演示了如何使用这种对象:
double wt = 125.8;
outFile << wt; //将一个数字写入fish.txt
char line[81] = "Objects are closer than they appear.";
fout << line << endl; //写入一行文本
重要的是,声明一个ofstream对象并将其同文件关联起来后,便可以像使用cout那样使用它。所有可用于cout的操作和方法(如<<、endl和setf())都可用于ofstream对象(如前述示例中的outFile和fout)。
使用文件输出的主要步骤如下:
- 包含头文件fstream
- 创建一个ofstream对象
- 将该ofstream对象同一个文件关联起来
- 像使用cout那样使用该ofstream对象
程序6.15
#include<iostream>
#include<fstream>
int main()
{
using namespace std;
char automobile[50];
int year;
double a_price;
double d_price;
ofstream outFile;
outFile.open("carinfo.txt");
cout << "Enter the make and model of automobile: ";
cin.getline(automobile, 50);
cout << "Enter the model year: ";
cin >> year;
cout << "Enter the orginal asking price: ";
cin >> a_price;
d_price = 0.913 * a_price;
cout << fixed;
cout.precision(2);
cout.setf(ios_base::showpoint);
cout << "Make and model: " << a_price << endl;
cout << "Year: " << year << endl;
cout << "Was asking $" << a_price << endl;
cout << "Now asking $" << d_price << endl;
outFile << fixed;
outFile.precision(2);
outFile.setf(ios_base::showpoint);
outFile << "Make and model: " << a_price << endl;
outFile << "Year: " << year << endl;
outFile << "Was asking $" << a_price << endl;
outFile << "Now asking $" << d_price << endl;
outFile.close();
system("pause");
return 0;
}
程序使用完文件后,应使用close()将其关闭。close()不需要文件名作为参数,因为outFile已经同特定的文件关联起来。
程序运行之前,carinfo.txt并不存在,这种情况下,open()将新建一个名为carinfo.txt的文件。如果文件carinfo.txt已经存在,open()将清空该文件,再将新的输出写入到该文件中。
读取文本文件
读取文本文件是基于控制台输入的。
控制台输入涉及以下方面:
- 必须包含头文件iostream
- 头文件iostream定义了一个用于处理输入的istream类
- 头文件iostream声明了一个名为cin的istream对象
- 必须指明名称空间std,using namespace std
- 可以结合使用cin和运算符>>来读取各种类型的数据
- 可以使用cin和get()来读取一个字符,使用cin和getline()来读取一行字符
- 对象cin本身被用作测试条件时,如果最后一个读取操作成功,将被转换为bool值true,否则为false
文件输出:
- 必须包含头文件fstream
- 头文件fstream定义了一个用于处理文件读取的ifstream类
- 需要声明一个或多个ifstream对象,并以合法的方式对其进行命名
- 必须指明名称空间std,using namespace std
- 需要将ifstream对象与文件关联起来,一种方法是使用open()
- 使用完文件后,应使用close()将文件关闭
- 可以结合使用ifstream对象和运算符>>来读取各种类型的数据
- 可以使用ifstream对象和get()来读取一个字符,使用ifstream对象和getline()来读取一行字符
- 可以结合使用ifstream对象和eof()、fail()等方法来判断输入是否成功
- ifstream对象本身被用作测试条件时,如果最后一个读取操作成功,将被转换为bool值true,否则为false
声明ifstream对象:
ifstream inFile;
ifstream fin;
将ifstream对象与特定的文件关联起来:
inFile.open("bowling.txt");
char filename[50];
cin >> filename;
fin.open(filename);
注意,方法open()接受一个C-风格字符串作为参数,这可以是一个字面字符串,也可以是存储在数组中的字符串。
使用ifstream对象:
double wt;
inFile >> wt;
char line[81];
fin.getline(line, 81);
重要的是,声明一个ifstream对象并将其同文件关联起来后,便可以像使用cin那样使用它。所有可用于cin的操作和方法都可用于ifstream对象(如前述示例中的inFile和fin)。
如果试图打开一个不存在的文件作为输入,将导致后面使用ifstream对象进行输入时失败。检查文件是否被成功打开的方法是使用is_open():
inFile.open("bowling.txt");
if (!inFile.is_open())
{
exit(EXIT_FAILURE);
}
函数exit()的原型是在头文件cstdlib中定义的,在该头文件中,还定义了一个用于同操作系统通信的参数值EXIT_FAILURE。函数exit()终止程序。
程序6.16
#include<iostream>
#include<fstream>
#include<cstdlib>
const int SIZE = 60;
int main()
{
using namespace std;
char filename[SIZE];
ifstream inFile;
cout << "Enter name of data file: ";
cin.getline(filename, SIZE);
inFile.open(filename);
if (!inFile.is_open())
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
double value;
double sum = 0.0;
int count = 0;
inFile >> value;
while (inFile.good())
{
++count;
sum += value;
inFile >> value;
}
if (inFile.eof())
cout << "End of file reached.\n";
else if (inFile.fail())
cout << "Input terminated by data mismatch.\n";
else
cout << "Input terminated for unknown reson.\n";
if (count == 0)
cout << "No data processed.\n";
else
{
cout << "Items read: " << count << endl;
cout << "Sum: " << sum << endl;
cout << "Average: " << sum / count << endl;
}
inFile.close();
system("pause");
return 0;
}
检查文件是否被成功打开至关重要。
good()在没有任何错误发生时返回true。