
在 C++ 编程中,文件的输入输出(I/O)操作是一项非常重要的功能。它允许将程序中的数据保存到文件中,以便后续使用或与其他程序共享;同时,也可以从文件中读取数据,供程序进行处理。C++ 标准 IO 库提供了强大而灵活的文件操作功能,通过使用这些功能,可以轻松地实现文件的创建、读取、写入和修改等操作。本文将详细介绍 C++ 标准 IO 库中文件输入输出的相关知识,包括文件流对象的使用、文件的打开和关闭、数据的读写操作以及错误处理等方面。
C++ 标准 IO 库中提供了三个主要的文件流类,分别用于不同类型的文件操作:
①ifstream(输入文件流):
②ofstream(输出文件流):
③fstream(文件流):
这些类都定义在 <fstream> 头文件中,因此在使用文件流对象之前,需要包含该头文件。
创建文件流对象的方式与创建其他对象类似,只需指定对象的类型和名称即可。以下是创建不同类型文件流对象的示例代码:
#include <fstream>
int main() {
// 创建一个用于读取文件的 ifstream 对象
std::ifstream inFile;
// 创建一个用于写入文件的 ofstream 对象
std::ofstream outFile;
// 创建一个既可以读取又可以写入文件的 fstream 对象
std::fstream ioFile;
return 0;
}在使用文件流对象进行文件操作之前,需要先打开文件。可以使用文件流对象的 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,该模式表示以写入方式打开文件。如果文件不存在,则会创建该文件;如果文件已经存在,则会清空文件内容。
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;
}
在完成文件操作后,需要关闭文件,以释放系统资源。可以使用文件流对象的 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;
}

逐行读取文本文件是一种常见的文件读取方式,可以使用 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 字符串中,然后输出到控制台。
读取二进制文件时,需要以二进制模式打开文件,并使用 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() 函数获取实际读取的字节数。
写入文本文件可以使用插入操作符 << 或 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。
写入二进制文件需要以二进制模式打开文件,并使用 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 的内容写入文件。
文件指针是一个指向文件中当前位置的指针,它决定了下一次读写操作的起始位置。在进行文件读写操作时,文件指针会自动向后移动。可以使用文件流对象的 tellg() 和 tellp() 函数来获取文件指针的当前位置,使用 seekg() 和 seekp() 函数来移动文件指针的位置。
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;
}
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 库提供了丰富的文件输入输出功能,通过使用文件流对象、合理选择打开模式、掌握文件的读写操作和文件指针的操作,以及进行错误处理,可以实现各种复杂的文件操作。在实际编程中,需要根据具体的需求选择合适的文件操作方式,并注意错误处理,以确保程序的健壮性和可靠性。
using声明在模板编程中有着重要应用,如定义模板类型别名等。