到目前为止,我们已经使用了 iostream 标准库,它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。
本教程介绍如何从文件读取流和向文件写入流。这就需要用到 C++ 中另一个标准库 fstream,它定义了三个新的数据类型:
数据类型 | 描述 |
---|---|
ofstream | 该数据类型表示输出文件流,用于创建文件并向文件写入信息。 |
ifstream | 该数据类型表示输入文件流,用于从文件读取信息。 |
fstream | 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 |
要在 C++ 中进行文件处理,必须在 C++ 源代码文件中包含头文件 <iostream> 和 <fstream>。
一、打开文件
在从文件读取信息或者向文件写入信息之前,必须先打开文件。ofstream 和 fstream 对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream 对象。
下面是 open() 函数的标准语法,open() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
cpp
void open(const char *filename, ios::openmode mode);
在这里,open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。
模式标志 | 描述 |
---|---|
ios::app | 追加模式。所有写入都追加到文件末尾。 |
ios::ate | 文件打开后定位到文件末尾。 |
ios::in | 打开文件用于读取。 |
ios::out | 打开文件用于写入。 |
ios::trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。 |
您可以把以上两种或两种以上的模式结合使用。例如,如果您想要以写入模式打开文件,并希望截断文件,以防文件已存在,那么您可以使用下面的语法:
cpp
ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );
类似地,您如果想要打开一个文件用于读写,可以使用下面的语法:
cpp
ifstream afile;
afile.open("file.dat", ios::out | ios::in );
1.2 示例
**`ofstream outfile` 是定义了一个名为 `outfile` 的输出文件流对象,用于将数据写入磁盘上的文件。**可以使用 `<<` 运算符向文件写入数据,例如:
cpp
#include<iostream>
#include<fstream>
int main(){
std::ofstream outfile("example.txt"); // 打开文件
outfile << "Hello, world!" << std::endl; // 向文件写入数据
outfile.close(); // 关闭文件
}
在这个例子中,`outfile` 对象被创建并打开了 `example.txt` 文件**(文件的路径可以指定,在上述程序中,我们没有指定文件的路径,则该文件会存放在该程序所存放的文件夹位置中)**,然后使用 `<<` 运算符向文件写入了 `"Hello, world!"` 字符串以及一个换行符,最后关闭了文件。该文件如打开如下图所示。
需要注意的是,如果文件不存在,则会创建该文件;如果文件已存在,则会将其覆盖。
**`ifstream afile;` 是定义了一个名为 `afile` 的输入文件流对象,用于从磁盘上的文件读取数据。**可以使用 `>>` 运算符从文件读取数据,例如:
cpp
#include<iostream>
#include<fstream>
#include<string>
int main() {
std::ifstream afile("example.txt"); // 打开文件
std::string line;
while (std::getline(afile, line)) { // 逐行读取文件内容 注意:必须引入<string>头文件才能正确使用getline函数
std::cout << line << std::endl; // 输出每一行内容
}
afile.close(); // 关闭文件
}
在这个例子中,`afile` 对象被创建并打开了 `example.txt` 文件,然后使用 `getline()` 函数将文件内容逐行读取到字符串变量 `line` 中,并输出到标准输出流中。最后关闭了文件。
上述程序输出结果:
需要注意的是,如果文件打开成功,则可以继续读取文件内容;如果文件不存在或无法打开,则需要进行错误处理。在读取文件时,可以根据具体需求选择不同的读取方式和处理方法来读取所需的数据。
关闭文件
当 C++ 程序终止时,它会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件。但程序员应该养成一个好习惯,在程序终止前关闭所有打开的文件。
下面是 close() 函数的标准语法,close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
cpp
void close();
写入文件
在 C++ 编程中,我们使用流插入运算符( << )向文件写入信息 ,就像使用该运算符输出信息到屏幕上一样。唯一不同的是,在这里您使用的是 ofstream 或 fstream 对象,而不是 cout 对象。
读取文件
在 C++ 编程中,我们使用流提取运算符( >> )从文件读取信息 ,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里您使用的是 ifstream 或 fstream 对象,而不是 cin 对象。
文件位置指针
在 C++ 中,文件位置指针(File Position Pointer)用于标识当前读写位置在文件中的位置。 C++ 标准库提供了两个主要的文件位置指针类型:std::ifstream
和 std::ofstream
,分别用于输入流和输出流。
ifstream 和 ofstream 都提供了用于重新定位文件位置指针的成员函数。这些成员函数包括关于 ifstream 的 seekg ("seek get")和关于 ofstream 的 seekp("seek put")。
seekg 和 seekp 的参数通常是一个长整型。第二个参数可以用于指定查找方向。查找方向可以是 ios::beg (默认的,从流的开头开始定位),也可以是 ios::cur (从流的当前位置开始定位),也可以是 ios::end(从流的末尾开始定位)。
文件位置指针是一个整数值,指定了从文件的起始位置到指针所在位置的字节数。下面是关于定位 "get" 文件位置指针的实例:
cpp
// 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
fileObject.seekg( n );
// 把文件的读指针从 fileObject 当前位置向后移 n 个字节
fileObject.seekg( n, ios::cur );
// 把文件的读指针从 fileObject 末尾往回移 n 个字节
fileObject.seekg( n, ios::end );
// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );
文件位置指针主要有以下三种操作:
<1> 定位到文件开头(seekg(0)
/ seekp(0)
):
cpp
std::ifstream inputFile("example.txt");
inputFile.seekg(0); // 将输入文件位置指针定位到文件开头
std::ofstream outputFile("example.txt");
outputFile.seekp(0); // 将输出文件位置指针定位到文件开头
seekg(0)
和 seekp(0)
将文件位置指针移动到文件的开头。
<2> 移动相对位置(seekg(offset, direction)
/ seekp(offset, direction)
):
cpp
std::ifstream inputFile("example.txt");
inputFile.seekg(10, std::ios::cur); // 相对于当前位置向前移动 10 个字节
std::ofstream outputFile("example.txt");
outputFile.seekp(-5, std::ios::end); // 相对于文件末尾向后移动 5 个字节
seekg(offset, direction)
和 seekp(offset, direction)
可以在文件中移动位置指针。offset
表示要移动的偏移量,可以是正数或负数。direction
指定了移动的方向,可以使用以下值:
std::ios::beg
:相对于文件开头进行偏移,默认值。std::ios::cur
:相对于当前位置进行偏移。std::ios::end
:相对于文件末尾进行偏移。
<3> 定位到文件末尾(seekg(0, std::ios::end)
/ seekp(0, std::ios::end)
):
cpp
std::ifstream inputFile("example.txt");
inputFile.seekg(0, std::ios::end); // 将输入文件位置指针定位到文件末尾
std::ofstream outputFile("example.txt");
outputFile.seekp(0, std::ios::end); // 将输出文件位置指针定位到文件末尾
seekg(0, std::ios::end)
和 seekp(0, std::ios::end)
将文件位置指针移动到文件的末尾。
注意:文件位置指针操作需要在打开文件后才能使用。另外,对于二进制文件,应该使用 std::ios::binary
模式打开文件来确保精确的指针操作。
示例
cpp
#include<iostream>
#include<fstream>
int main() {
std::ofstream outfile("D:/桌面资料/研究生阶段/C++Learning_road/C++file_test/example.txt"); // 打开文件
outfile << "Hello, world!"; // 向文件写入数据
outfile.seekp(0); // 将文件位置指针移动到文件的开头
outfile.seekp(5, std::ios::cur); // 相对于当前位置向前移动 5 个字节
outfile << "世界,你好!" << std::endl; // 向文件写入数据
outfile.close(); // 关闭文件
return 0;
}
运行上述程序,得到如下结果:
程序分析:
这段代码首先创建了一个名为 "D:/桌面资料/研究生阶段/C++Learning_road/C++file_test/example.txt" 的文件输出流对象 `outfile`,然后向文件中写入了字符串 "Hello, world!"。接下来,代码将文件位置指针移动到文件开头,然后相对于当前位置向前**(向前的原理如下图所示)**移动 5 个字节。最后,代码向文件中写入了字符串 "世界,你好!" 并添加了一个换行符。
需要注意的是,`seekp(0)` 将文件位置指针移动到文件开头,然后 `seekp(5, std::ios::cur)` 将文件位置指针相对于当前位置向前移动 5 个字节,因此,最终的文件位置指针指向了字符 'w'。
通过执行这段代码,你将会在指定路径的 example.txt 文件中得到以下内容:
cpp
Hello世界,你好!
最后,通过调用 `outfile.close()` 关闭文件。关闭文件是一个好的习惯,可以确保文件资源被正确释放,同时也可以确保文件的写入操作已经完成。