【C++标准IO库】文件的输入输出
目录
一、文件流对象
1.1 文件流类的介绍
1.2 文件流对象的创建
二、文件的打开和关闭
2.1 文件的打开
2.2 打开模式
2.3 文件的关闭
三、文件的读取操作
3.1 逐行读取文本文件
3.2 读取二进制文件
四、文件的写入操作
4.1 写入文本文件
4.2 写入二进制文件
五、文件指针的操作
5.1 文件指针的概念
5.2 获取文件指针的位置
5.3 移动文件指针的位置
六、错误处理
七、总结
八、参考资料
在 C++ 编程中,文件的输入输出(I/O)操作是一项非常重要的功能。它允许将程序中的数据保存到文件中,以便后续使用或与其他程序共享;同时,也可以从文件中读取数据,供程序进行处理。C++ 标准 IO 库提供了强大而灵活的文件操作功能,通过使用这些功能,可以轻松地实现文件的创建、读取、写入和修改等操作。本文将详细介绍 C++ 标准 IO 库中文件输入输出的相关知识,包括文件流对象的使用、文件的打开和关闭、数据的读写操作以及错误处理等方面。
一、文件流对象
1.1 文件流类的介绍
C++ 标准 IO 库中提供了三个主要的文件流类,分别用于不同类型的文件操作:
①ifstream
(输入文件流):
- 用途:用于从文件读取数据。
- 特点:默认以读模式打开文件,支持文本文件和二进制文件的读取操作。
②ofstream
(输出文件流):
- 用途:用于向文件写入数据。
- 特点:默认以写模式打开文件,支持文本文件和二进制文件的写入操作。
③fstream
(文件流):
- 用途:既可以读取数据,也可以写入数据。
- 特点:默认以读写模式打开文件,支持文本文件和二进制文件的读写操作。
这些类都定义在 <fstream>
头文件中,因此在使用文件流对象之前,需要包含该头文件。
1.2 文件流对象的创建
创建文件流对象的方式与创建其他对象类似,只需指定对象的类型和名称即可。以下是创建不同类型文件流对象的示例代码:
#include <fstream>
int main() {
// 创建一个用于读取文件的 ifstream 对象
std::ifstream inFile;
// 创建一个用于写入文件的 ofstream 对象
std::ofstream outFile;
// 创建一个既可以读取又可以写入文件的 fstream 对象
std::fstream ioFile;
return 0;
}
二、文件的打开和关闭
2.1 文件的打开
在使用文件流对象进行文件操作之前,需要先打开文件。可以使用文件流对象的 open()
成员函数来打开文件,该函数接受两个参数:文件名和打开模式。文件名可以是相对路径或绝对路径,打开模式指定了文件的打开方式,如只读、只写、追加等。以下是打开文件的示例代码:
#include <fstream>
#include <iostream>
int main() {
// 创建一个 ofstream 对象
std::ofstream outFile;
// 打开一个文件用于写入,如果文件不存在则创建它
outFile.open("example.txt", std::ios::out);
if (outFile.is_open()) {
std::cout << "文件打开成功!" << std::endl;
} else {
std::cout << "文件打开失败!" << std::endl;
}
// 关闭文件
outFile.close();
return 0;
}
使用 open()
函数以 std::ios::out
模式打开文件 example.txt
,该模式表示以写入方式打开文件。如果文件不存在,则会创建该文件;如果文件已经存在,则会清空文件内容。
2.2 打开模式
C++ 标准 IO 库定义了多种打开模式,这些模式可以通过按位或运算符 |
组合使用,以满足不同的需求。常见的打开模式如下表:
模式标志 | 说明 |
---|---|
std::ios::in | 读方式打开(ifstream默认),用于读取文件内容。 |
std::ios::out | 写方式打开(ofstream默认),如果文件不存在则创建它,如果文件已经存在则清空文件内容。 |
std::ios::binary | 二进制模式(默认文本模式) |
std::ios::ate | 打开文件后将文件指针定位到文件末尾,但仍然可以进行读写操作。 |
std::ios::app | 追加模式(自动定位到末尾),所有写入操作都会在文件末尾进行,不会清空文件原有内容。 |
std::ios::trunc | 截断文件(默认如果存在则清空) |
以下是使用组合打开模式的示例代码:
#include <fstream>
#include <iostream>
int main() {
// 以读写方式打开文件,如果文件不存在则创建它,并且不清空原有内容
std::fstream ioFile("example.txt", std::ios::in | std::ios::out | std::ios::app);
if (ioFile.is_open()) {
std::cout << "文件打开成功!" << std::endl;
} else {
std::cout << "文件打开失败!" << std::endl;
}
// 关闭文件
ioFile.close();
return 0;
}
2.3 文件的关闭
在完成文件操作后,需要关闭文件,以释放系统资源。可以使用文件流对象的 close()
成员函数来关闭文件。以下是关闭文件的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::ofstream outFile("example.txt");
if (outFile.is_open()) {
// 写入数据到文件
outFile << "Hello, World!";
// 关闭文件
outFile.close();
std::cout << "文件已关闭!" << std::endl;
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
三、文件的读取操作
3.1 逐行读取文本文件
逐行读取文本文件是一种常见的文件读取方式,可以使用 std::getline()
函数来实现。该函数接受两个参数:文件流对象和一个字符串对象,用于存储读取到的一行文本。以下是逐行读取文本文件的示例代码:
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream inFile("example.txt");
if (inFile.is_open()) {
std::string line;
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
// 关闭文件
inFile.close();
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
使用 std::getline()
函数逐行读取文件 example.txt
的内容,并将每行内容存储在 line
字符串中,然后输出到控制台。
3.2 读取二进制文件
读取二进制文件时,需要以二进制模式打开文件,并使用 read()
成员函数来读取数据。read()
函数接受两个参数:一个指向存储数据的缓冲区的指针和要读取的字节数。以下是读取二进制文件的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::ifstream inFile("example.bin", std::ios::binary);
if (inFile.is_open()) {
// 定义一个缓冲区
char buffer[1024];
// 读取数据到缓冲区
inFile.read(buffer, sizeof(buffer));
// 获取实际读取的字节数
std::streamsize bytesRead = inFile.gcount();
std::cout << "读取了 " << bytesRead << " 字节的数据。" << std::endl;
// 关闭文件
inFile.close();
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
以二进制模式打开文件 example.bin
,并使用 read()
函数将文件内容读取到 buffer
缓冲区中,最后使用 gcount()
函数获取实际读取的字节数。
四、文件的写入操作
4.1 写入文本文件
写入文本文件可以使用插入操作符 <<
或 write()
成员函数。插入操作符 <<
可以方便地将各种数据类型写入文件,而 write()
函数主要用于写入二进制数据。以下是使用插入操作符写入文本文件的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::ofstream outFile("example.txt");
if (outFile.is_open()) {
// 写入字符串
outFile << "Hello, World!" << std::endl;
// 写入整数
int num = 123;
outFile << "The number is: " << num << std::endl;
// 关闭文件
outFile.close();
std::cout << "数据写入成功!" << std::endl;
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
使用插入操作符 <<
将字符串和整数写入文件 example.txt
。
4.2 写入二进制文件
写入二进制文件需要以二进制模式打开文件,并使用 write()
成员函数。write()
函数接受两个参数:一个指向要写入数据的缓冲区的指针和要写入的字节数。以下是写入二进制文件的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::ofstream outFile("example.bin", std::ios::binary);
if (outFile.is_open()) {
// 定义一个整数数组
int numbers[] = {1, 2, 3, 4, 5};
// 计算数组的字节数
std::streamsize size = sizeof(numbers);
// 写入数据到文件
outFile.write(reinterpret_cast<const char*>(numbers), size);
// 关闭文件
outFile.close();
std::cout << "数据写入成功!" << std::endl;
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
以二进制模式打开文件 example.bin
,并使用 write()
函数将整数数组 numbers
的内容写入文件。
五、文件指针的操作
5.1 文件指针的概念
文件指针是一个指向文件中当前位置的指针,它决定了下一次读写操作的起始位置。在进行文件读写操作时,文件指针会自动向后移动。可以使用文件流对象的 tellg()
和 tellp()
函数来获取文件指针的当前位置,使用 seekg()
和 seekp()
函数来移动文件指针的位置。
5.2 获取文件指针的位置
tellg()
函数用于获取输入文件指针的当前位置,tellp()
函数用于获取输出文件指针的当前位置。这两个函数返回一个 std::streampos
类型的值,表示文件指针的位置。以下是获取文件指针位置的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::fstream ioFile("example.txt", std::ios::in | std::ios::out);
if (ioFile.is_open()) {
// 获取输入文件指针的当前位置
std::streampos pos = ioFile.tellg();
std::cout << "输入文件指针的当前位置: " << pos << std::endl;
// 获取输出文件指针的当前位置
pos = ioFile.tellp();
std::cout << "输出文件指针的当前位置: " << pos << std::endl;
// 关闭文件
ioFile.close();
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
5.3 移动文件指针的位置
seekg()
函数用于移动输入文件指针的位置,seekp()
函数用于移动输出文件指针的位置。这两个函数接受两个参数:要移动的偏移量和偏移的起始位置。偏移的起始位置可以是 std::ios::beg
(文件开头)、std::ios::cur
(当前位置)或 std::ios::end
(文件末尾)。以下是移动文件指针位置的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::fstream ioFile("example.txt", std::ios::in | std::ios::out);
if (ioFile.is_open()) {
// 将输入文件指针移动到文件开头偏移 5 个字节的位置
ioFile.seekg(5, std::ios::beg);
// 获取输入文件指针的当前位置
std::streampos pos = ioFile.tellg();
std::cout << "输入文件指针的当前位置: " << pos << std::endl;
// 将输出文件指针移动到文件末尾偏移 -3 个字节的位置
ioFile.seekp(-3, std::ios::end);
// 获取输出文件指针的当前位置
pos = ioFile.tellp();
std::cout << "输出文件指针的当前位置: " << pos << std::endl;
// 关闭文件
ioFile.close();
} else {
std::cout << "文件打开失败!" << std::endl;
}
return 0;
}
六、错误处理
在进行文件操作时,可能会遇到各种错误,如文件打开失败、读写错误等。可以使用文件流对象的状态标志来检查文件操作是否成功。常见的状态标志有:
good()
:检查流是否处于正常状态。eof()
:检查是否到达文件末尾。fail()
:检查是否发生了可恢复的错误。bad()
:检查是否发生了严重的错误。
以下是一个错误处理的示例代码:
#include <fstream>
#include <iostream>
int main() {
std::ifstream inFile("nonexistent.txt");
if (!inFile.good()) {
if (inFile.fail()) {
std::cout << "文件打开失败,可能是文件不存在。" << std::endl;
} else if (inFile.bad()) {
std::cout << "发生了严重的错误!" << std::endl;
}
} else {
// 进行文件操作
inFile.close();
}
return 0;
}
尝试打开一个不存在的文件,通过检查 good()
、fail()
和 bad()
状态标志来判断文件打开是否成功,并输出相应的错误信息。
七、总结
C++ 标准 IO 库提供了丰富的文件输入输出功能,通过使用文件流对象、合理选择打开模式、掌握文件的读写操作和文件指针的操作,以及进行错误处理,可以实现各种复杂的文件操作。在实际编程中,需要根据具体的需求选择合适的文件操作方式,并注意错误处理,以确保程序的健壮性和可靠性。
八、参考资料
- 《C++ Primer(第 5 版)》这本书是 C++ 领域的经典之作,对 C++ 的基础语法和高级特性都有深入讲解。
- 《Effective C++(第 3 版)》书中包含了很多 C++ 编程的实用建议和最佳实践。
- 《C++ Templates: The Complete Guide(第 2 版)》该书聚焦于 C++ 模板编程,而
using
声明在模板编程中有着重要应用,如定义模板类型别名等。 - C++ 官方标准文档:C++ 标准文档是最权威的参考资料,可以查阅最新的 C++ 标准(如 C++11、C++14、C++17、C++20 等)文档。例如,ISO/IEC 14882:2020 是 C++20 标准的文档,可从相关渠道获取其详细内容。
- cppreference.com:这是一个非常全面的 C++ 在线参考网站,提供了详细的 C++ 语言和标准库文档。
- LearnCpp.com:该网站提供了系统的 C++ 教程,配有丰富的示例代码和清晰的解释,适合初学者学习和理解相关知识。