open函数和close函数的使用方法
#include <iostream>
#include <exception>
#include <fstream>
#include <cstring>
using namespace std;
int main() {
const char *text = "niu brother is so good\n";
const char *text_2 = "niu brother is a good man\n";
ofstream outfile;
outfile.open("D://cpp_text.txt", ios::out);
outfile.write(text, strlen(text));
outfile.write(text_2, strlen(text_2));
outfile.close();
cout << strlen(text) << endl;
return 0;
}
输出:
23
上述输出的是字符串数组的长度,运行程序生成的文件存在本地的D盘中,文件中的具体内容展示为:
已知fstream是ios基类的最终的间接派生类,所以它继承了ios基类的所有成员(私有成员除外),ios基类直接派生出了ostream类和istream类,而ostream类派生出了ofstream类和iostream类,istream类派生出了ifstream类和iostream类,而fstream是iostream的派生类。所以fstream拥有istream,ostream,iostream,ios基类的全部成员。
open()有两个参数,第一个参数是指向文件名的指针,第二个参数是打开文件的模式,这里定义为写入模型。注:若一开始不存在打开的文件,系统会自动创建该文件再写入。
下面来看一下文件打开的各种模式
模式标记 | 适用对象 | 作用 |
---|---|---|
ios::in | ifstream fstream | 打开文件用于读取数据,如果文件不存在,则打开出错 |
ios::out | ofstream fstream | 打开文件用于写入数据,如果文件不存在,则新建该文件,如果文件存在,则打开时清除原来的内容。 |
ios::app | ofstream fstream | 打开文件,用于在其尾部添加数据,如果文件不存在,则新建该文件。 |
ios::ate | ifstream | 打开一个已有的文件,并将文件读指针指向文件末尾,如果文件不存在,则打开出错。 |
ios::trunc | ofstream | 打开文件时会清空内部存储的所有数据,单独使用时与ios::out相同。 |
ios::binary | ifstream ofstream fstream | 以二进制方式打开文件。若不指定此模式,则以文本模式打开。 |
ios::in丨ios::out | fstream | 打开已存在的文件,既可读取其内容,也可向其写入数据。文件刚打开时,原有内容保持不变,如果文件不存在,则打开出错。 |
ios::in 丨 ios::out | ofstream | 打开已存在的文件,可以向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开出错。 |
ios::in 丨ios::out 丨ios::trunc | fstream | 打开文件,既可读取其内容,也可向其写入数据。如果文件本来就存在,则打开时清除原来的内容,若文件不存在,则新建该文件。 |
ios::binary 可以和其他模式标记组合使用,例如:
ios::in | ios::binary 表示二进制模式以读取的方式打开
ios::out | ios::binary 表示二进制模式以写入的方式打开
我们知道,调用 open() 方法打开文件,是文件流对象和文件之间建立关联的过程。那么,调用 close() 方法关闭已打开的文件,就可以理解为是切断文件流对象和文件之间的关联。注意,close() 方法的功能仅是切断文件流与文件之间的关联,该文件流并会被销毁,其后续还可用于关联其它的文件。打开的文件流用完之后一定要close掉,不然会造成内存泄漏的风险。
文本文件读写操作详解
上面已经介绍过文件流对象如何调用open()打开文件,并在I/O文件操作结束后,调用close()方法关闭先前打开的文件。那么如何对文件内容实现读写呢?下面来详细介绍一下。
对文件的I/O操作可以细分为两类,分别是以文本形式读写文件和以二进制形式读写文件。
1.我们知道,文件中存储的数据并没有类型上的分别,统统都是字符。所谓以文本形式读/写文件,就是直白地将文件中存储的字符(或字符串)读取出来,以及将目标字符(或字符串)存储在文件中。
2.而以二进制形式读/写文件,操作的对象不再是打开文件就能看到的字符,而是文件底层存储的二进制数据。更详细地讲,当以该形式读取文件时,读取的是该文件底层存储的二进制数据;同样,当将某数据以二进制形式写入到文件中时,写入的也是其对应的二进制数据。
举个例子,假设我们以文本形式将浮点数 19.625 写入文件,则该文件会直接将 “19.625” 这个字符串存储起来。当我们双击打开此文件,也可以看到 19.625。值得一提的是,由非字符串数据(比如这里的浮点数 19.625)转换为对应字符串(转化为 “19.625”)的过程,C++ 标准库已经实现好了,不需要我们操心。
但如果以二进制形式将浮点数 19.625 写入文件,则该文件存储的不再是 “19.625” 这个字符串,而是 19.625 浮点数对应的二进制数据。
0100 0001 1001 1101 0000 0000 0000 0000
显然,如果直接将以上二进制数据转换为 float 类型,仍可以得到浮点数 19.625。但对于文件来说,它只会将存储的二进制数据根据既定的编码格式(如 utf-8、gbk 等)转换为一个个字符。这也就意味着,如果我们直接打开此文件,看到的并不会是 19.625,往往是一堆乱码。
C++ 标准库中,提供了 2 套读写文件的方法组合,分别是:
1.使用 >> 和 << 读写文件:适用于以文本形式读写文件;
2.使用 read() 和 write() 成员方法读写文件:适用于以二进制形式读写文件。
C++ >>和<<读写文本文件
我们知道fstream 或者 ifstream 类负责实现对文件的读取,它们内部都对 >> 输出流运算符做了重载;同样,fstream 和 ofstream 类负责实现对文件的写入,它们的内部也都对 << 输出流运算符做了重载。
所以,当 fstream 或者 ifstream 类对象打开文件(通常以 ios::in 作为打开模式)之后,就可以直接借助 >> 输入流运算符,读取文件中存储的字符(或字符串);当 fstream 或者 ofstream 类对象打开文件(通常以 ios::out 作为打开模式)后,可以直接借助 << 输出流运算符向文件中写入字符(或字符串)。
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main() {
int x;
int sum = 0;
ofstream ofs;
ifstream ifs;
const char *read_src = "D://cpp_text.txt";
const char *write_src = "D://cpp_write.txt";
const char *init_text = "20 30 60\n50 20";
ofs.open(read_src, ios::out);
ofs.write(init_text, strlen(init_text));
ofs.close();
try {
ifs.open(read_src, ios::in);
ofs.open(write_src, ios::out);
while (ifs >> x) {
sum += x;
cout << "x_in:" << x << endl;
ofs << x << "\n";
}
cout << "sum:" << sum << endl;
} catch (exception &e) {
cout << "failed the open the file" << endl;
}
ifs.close();
ofs.close();
ifs.open(write_src, ios::in);
while (ifs >> x) {
cout << "x_out:" << x << endl;
}
ifs.close();
return 0;
}
输出:
x_in:20
x_in:30
x_in:60
x_in:50
x_in:20
sum:180
x_out:20
x_out:30
x_out:60
x_out:50
x_out:20
执行此程序之前,必须在和系统中对应的硬盘下中手动创建一个 cpp_text.txt 文件,假设其内部存储的字符串为:
10 20 60
50 20
建立之后,执行程序,其执行结果为:
sum:180
同时在 cpp_text.txt 文件同目录下,会生成一个 cpp_write.txt 文件,其内部存储的每一个字符都独占一行。
通过分析程序的执行结果不难理解,对于 cpp_text.txt 文件中的"10 20 30 40 50"
字符串,ifs对象会依次将"10"、“20”、“30”、“40”、“50” 读取出来,将它们解析成 int 类型的整数 10、20、30、40、50 并赋值给 x,同时完成和 sum 的加和操作。
同样,对于每次从 cpp_text.txt 文件读取并解析出的整型 x,ofs对象都会原封不动地将其再解析成对应的字符串(如整数 10 解析成字符串 “10”),然后和 " " 空格符一起写入 cpp_write.txt 文件。