【和春笋一起学C++】文本文件I/O
在windows系统中读取键盘的输入和在屏幕上显示输出统称为:控制台输入/输出。把读取文本文件和把字符输出到文本文件中统称为:文本文件I/O。
目录
1. 输出文本文件
2. 读取文本文件
1. 输出文本文件
把字符输出到文本文件中和输出到控制台很相似,在C++中可以使用cout对象将字符输出到控制台。包含如下步骤:
- 包含头文件:#include <iostream>
- 指定命名空间:using namespace std;
- 使用cout和输出操作符<<将各种类型的数据输出到控制台
C++中将各种类型的数据输出到文本文件的步骤如下:
- 包含头文件:#include <fstream>
- 指定命名空间:using namespace std;
- 创建一个ofstream对象;
- 将ofstream对象与输出文件关联起来,方法之一是使用open()方法;
- 结合使用ofstream对象和输出操作符<<可以将各种类型的数据输出到文本文件中;
- 使用完文件后,应使用close()方法将其关闭;
示例:
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;int main()
{ofstream outfile;outfile.open("testfile.txt");outfile << "today is sunday" << endl;outfile << "the time is 20:00" << endl;outfile.close();return 0;
}
头文件iostream提供了预先定义好的在控制台输出的对象——cout,但对于文件输出,需要定义自己的ofstream对象,并将其同输出文件关联起来。所有可用于cout的操作和方法(如:<<,endl和setf())都可用于ofstream对象。
示例中,方法close()不需要使用文件名作为参数,因为outfile对象在使用open()方法时已经同特定的文件关联起来了。如果忘记关闭文件,那么在程序正常终止时将自动关闭它。在程序运行前,如文件不存在,则方法open()将新建一个文件。如文件已存在,默认情况下,open()方法将首先截断该文件,即将其长度截短到零,丢掉其原先的内容,然后将新的输出加入到该文件中。
注:有些情况下,打开文件会失败,如文件已存在且为只读文件。此时,需要程序员检测打开文件的操作是否成功。
2. 读取文本文件
先复习下控制台输入文本的步骤:
- 包含头文件iostream
- 指定命名空间std
- cin和输入操作符>>可以读取任何类型的数据;
- 使用cin.get()方法读取一个字符,cin.getline()方法读取一行字符,cin.eof(),cin.fail()方法可以用来判断输入是否成功。
详细可以看我的文章《文本输入与读取(二)》
文件输入与控制台文本输入很相似,步骤如下:
- 包含头文件fstream
- 定义ifstream类对象
- 指定命名空间std
- 将ifstream对象与文件关联起来,方法是使用open()方法
- 使用完文件,应使用close()方法将其关闭
- ifstream对象的方法与cin对象的方法完全相同,使用ifstream对象和输入操作符>>读取数据,ifstream对象的get()方法读取一个字符,getline()方法读取一行字符。
读取文件时,可以先用ifstream类对象的is_open()方法检测文件是否成功打开,否则如果读取了一个不存在的文件,将导致输入失败。如果文件成功打开,方法is_open()将返回ture,反之如果文件没有成功打开,is_open()将返回false。(一些老的编译器如果不支持is_open()方法,可以用good()方法代替)
示例:
#include <iostream>
#include <fstream>
#include <cstring>using namespace std;int main()
{ifstream inFile;string filePath = "test.txt";inFile.open(filePath);if (!inFile.is_open()){cout << "could not open the file: " << filePath << endl;exit(EXIT_FAILURE);}double value;double sum = 0.0;int count = 0;inFile >> value;while (inFile.good()){cout << value << " ";++count;sum += value;inFile >> value;}cout << endl;if (inFile.eof()){cout << "end of file reached.\n";}else if(inFile.fail()){cout << "input terminated by data mismatch.\n";}else{cout << "input terminated by unknow reason.\n";}if (count == 0){cout << "no data processed.\n";}else{cout << "sum: " << sum << endl;cout << "average: " << sum / count << endl;}inFile.close();return 0;
}
程序输出:
程序说明:
- 程序是读取一个文件中的数据,并求平均值,读取的文本文件中数据如下:
需要注意的是:对于windows文本文件,每行的末尾必须要有一个换行符,在自己新建test.txt文件时,请在输入文本后按下回车键,然后再保存文件。
- 程序首先检测文件是否被成功打开,如果没有成功打卡,则直接退出。函数exit()的原型是在头文件cstdlib中定义的,在该头文件中还定义了一个同操作系统通信的参数值:EXIT_FAILURE。函数exit()表示退出程序。
- 特别需要注意的是读取循环的设计,程序读取文件时不应超过EOF,如果最后一次读取数据时遇到EOF,方法eof()将返回true。其次可能遇到类型不匹配的情况,如果最后一次读取操作中遇到了类型不匹配的情况,方法fail()将返回true(如果遇到了EOF,该方法也将返回true。fail()方法既可以检测EOF,也可以检测类型不匹配问题)。最后一些预期外的东西也可能导致读取数据失败,例如文件受损、硬盘故障。
- 方法good()指出最后一次读取输入操作是否成功,这一点至关重要。这意味着应该在执行读取输入操作后,立刻应用这种测试。为此,一种标准的做法是在循环之前(首次执行循环测试前)放置一条输入语句,并在循环的末尾(下次执行循环测试前)放置另一条输入语句。如下:
inFile >> value;while (inFile.good()){cout << value << " ";++count;sum += value;inFile >> value;}
拓展:表达式inFile >> value的结果为inFile,而在需要一个bool值的情况下,inFile的结果为inFile.good(),即true或false。因此,可以将两条输入语句用一条用作循环测试的输入语句代替。如下:
while (inFile >> value){++count;sum += value;cout << value << " ";}
这种设计仍然遵循了在测试之前进行读取的规则,因为要计算表达式inFile >> value的值,程序必须首先将一个数字读取到value中。示例代码修改如下:
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{ifstream inFile;string filePath = "test.txt";inFile.open(filePath);if (!inFile.is_open()){cout << "could not open the file: " << filePath << endl;exit(EXIT_FAILURE);}double value;double sum = 0.0;int count = 0;while (inFile >> value){++count;sum += value;cout << value << " ";}cout << endl;if (inFile.eof()){cout << "end of file reached.\n";}else if(inFile.fail()){cout << "input terminated by data mismatch.\n";}else{cout << "input terminated by unknow reason.\n";}if (count == 0){cout << "no data processed.\n";}else{cout << "sum: " << sum << endl;cout << "average: " << sum / count << endl;}inFile.close();return 0;
}