C++ 文件和流
文件流概述
C++ 提供了三个主要的文件流类用于文件操作:
- ifstream - 输入文件流(从文件读取)
- ofstream - 输出文件流(写入文件)
- fstream - 文件流(读写操作)
基本文件操作
打开文件
cpp
#include <fstream>
#include <iostream>
int main() {
// 方法1: 构造函数
std::ofstream outfile1("example.txt");
// 方法2: open() 函数
std::ofstream outfile2;
outfile2.open("example.txt");
return 0;
}打开模式
cpp
// in - 以读取模式打开
std::ifstream file("data.txt", std::ios::in);
// out - 以写入模式打开
std::ofstream file("data.txt", std::ios::out);
// app - 追加模式
std::ofstream file("data.txt", std::ios::app);
// ate - 定位到文件末尾
std::fstream file("data.txt", std::ios::in | std::ios::out | std::ios::ate);
// trunc - 截断文件(删除内容)
std::ofstream file("data.txt", std::ios::out | std::ios::trunc);
// binary - 二进制模式
std::ofstream file("data.bin", std::ios::out | std::ios::binary);检查文件状态
cpp
std::ifstream file("data.txt");
if (!file.is_open()) {
std::cerr << "Error opening file!" << std::endl;
return 1;
}
if (file.good()) {
std::cout << "File stream is good" << std::endl;
}
if (file.eof()) {
std::cout << "End of file reached" << std::endl;
}写入文件
写入文本
cpp
#include <fstream>
#include <iostream>
int main() {
std::ofstream outfile("output.txt");
if (!outfile.is_open()) {
std::cerr << "Error opening file!" << std::endl;
return 1;
}
// 使用 << 运算符
outfile << "Hello, World!" << std::endl;
outfile << "This is C++ file writing." << std::endl;
// 写入变量
int number = 42;
double pi = 3.14159;
outfile << "Number: " << number << std::endl;
outfile << "Pi: " << pi << std::endl;
outfile.close();
return 0;
}格式化输出
cpp
std::ofstream outfile("formatted.txt");
// 设置宽度
outfile << std::setw(10) << "Name" << std::setw(10) << "Age" << std::endl;
outfile << std::setw(10) << "John" << std::setw(10) << 25 << std::endl;
// 精度控制
outfile << std::fixed << std::setprecision(2) << 3.14159 << std::endl;
// 填充字符
outfile << std::setfill('-') << std::setw(10) << "Test" << std::endl;读取文件
逐行读取
cpp
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream infile("input.txt");
if (!infile.is_open()) {
std::cerr << "Error opening file!" << std::endl;
return 1;
}
std::string line;
int line_number = 0;
while (std::getline(infile, line)) {
line_number++;
std::cout << "Line " << line_number << ": " << line << std::endl;
}
infile.close();
return 0;
}逐词读取
cpp
std::ifstream infile("input.txt");
std::string word;
while (infile >> word) {
std::cout << word << std::endl;
}读取数值
cpp
std::ifstream infile("numbers.txt");
int number;
while (infile >> number) {
std::cout << "Read: " << number << std::endl;
}读取结构化数据
cpp
struct Person {
std::string name;
int age;
double salary;
};
std::ifstream infile("people.txt");
Person p;
while (infile >> p.name >> p.age >> p.salary) {
std::cout << p.name << " - Age: " << p.age
<< ", Salary: " << p.salary << std::endl;
}文件定位
获取当前位置
cpp
std::ifstream infile("data.txt");
// 获取读取位置
std::streampos pos = infile.tellg();
std::cout << "Current position: " << pos << std::endl;设置位置
cpp
std::ifstream infile("data.txt");
// 绝对定位
infile.seekg(0, std::ios::beg); // 文件开头
infile.seekg(0, std::ios::end); // 文件末尾
infile.seekg(100); // 第100个字节
// 相对定位
infile.seekg(50, std::ios::cur); // 从当前位置向前移动50字节
infile.seekg(-50, std::ios::cur); // 从当前位置向后移动50字节获取文件大小
cpp
std::ifstream infile("data.txt", std::ios::binary | std::ios::ate);
std::streamsize size = infile.tellg();
std::cout << "File size: " << size << " bytes" << std::endl;二进制文件操作
写入二进制数据
cpp
#include <fstream>
#include <vector>
struct Data {
int id;
double value;
char name[20];
};
int main() {
Data data = {1, 3.14159, "Binary Data"};
std::ofstream outfile("data.bin", std::ios::binary);
// 写入单个对象
outfile.write(reinterpret_cast<char*>(&data), sizeof(Data));
// 写入数组
std::vector<int> numbers = {1, 2, 3, 4, 5};
outfile.write(reinterpret_cast<char*>(numbers.data()),
numbers.size() * sizeof(int));
outfile.close();
return 0;
}读取二进制数据
cpp
#include <fstream>
#include <vector>
struct Data {
int id;
double value;
char name[20];
};
int main() {
std::ifstream infile("data.bin", std::ios::binary);
// 读取单个对象
Data data;
infile.read(reinterpret_cast<char*>(&data), sizeof(Data));
std::cout << "ID: " << data.id << std::endl;
std::cout << "Value: " << data.value << std::endl;
std::cout << "Name: " << data.name << std::endl;
// 读取数组
std::vector<int> numbers(5);
infile.read(reinterpret_cast<char*>(numbers.data()),
numbers.size() * sizeof(int));
infile.close();
return 0;
}错误处理
检查错误状态
cpp
std::ifstream file("data.txt");
if (file.fail()) {
std::cerr << "Error occurred!" << std::endl;
}
if (file.bad()) {
std::cerr << "Critical error occurred!" << std::endl;
}清除错误状态
cpp
std::ifstream file("data.txt");
if (file.fail()) {
file.clear(); // 清除错误状态
file.seekg(0, std::ios::beg); // 重置文件位置
}异常处理
cpp
std::ifstream file("data.txt");
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// 文件操作
std::string line;
std::getline(file, line);
} catch (const std::ifstream::failure& e) {
std::cerr << "Exception opening/reading file: " << e.what() << std::endl;
}文件操作示例
复制文件
cpp
#include <fstream>
bool copyFile(const std::string& source, const std::string& dest) {
std::ifstream src(source, std::ios::binary);
std::ofstream dst(dest, std::ios::binary);
if (!src.is_open() || !dst.is_open()) {
return false;
}
dst << src.rdbuf();
return true;
}读取配置文件
cpp
#include <fstream>
#include <map>
#include <sstream>
std::map<std::string, std::string> readConfig(const std::string& filename) {
std::map<std::string, std::string> config;
std::ifstream file(filename);
std::string line;
while (std::getline(file, line)) {
if (line.empty() || line[0] == '#') continue;
size_t pos = line.find('=');
if (pos != std::string::npos) {
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1);
config[key] = value;
}
}
return config;
}统计文件信息
cpp
#include <fstream>
void countFileStats(const std::string& filename) {
std::ifstream file(filename);
int lines = 0, words = 0, chars = 0;
std::string word;
while (file >> word) {
words++;
chars += word.length();
}
file.clear();
file.seekg(0, std::ios::beg);
std::string line;
while (std::getline(file, line)) {
lines++;
}
std::cout << "Lines: " << lines << std::endl;
std::cout << "Words: " << words << std::endl;
std::cout << "Characters: " << chars << std::endl;
}最佳实践
RAII 模式
cpp
#include <fstream>
#include <string>
void processFile(const std::string& filename) {
std::ifstream file(filename); // 自动在作用域结束时关闭
if (!file.is_open()) {
return;
}
// 文件操作
}资源管理
cpp
#include <fstream>
#include <memory>
void safeFileOperation(const std::string& filename) {
std::unique_ptr<std::ifstream> file =
std::make_unique<std::ifstream>(filename);
if (!file->is_open()) {
throw std::runtime_error("Failed to open file");
}
// 文件操作
// 文件在 unique_ptr 销毁时自动关闭
}临时文件
cpp
#include <fstream>
#include <cstdio>
void useTempFile() {
// 创建临时文件
std::FILE* tmp = std::tmpfile();
if (tmp) {
std::fprintf(tmp, "Temporary data\n");
std::rewind(tmp); // 重置文件指针
char buffer[256];
while (std::fgets(buffer, sizeof(buffer), tmp)) {
std::cout << buffer;
}
std::fclose(tmp); // 文件自动删除
}
}文件系统操作(C++17)
cpp
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void fileSystemOperations() {
// 检查文件是否存在
if (fs::exists("test.txt")) {
std::cout << "File exists" << std::endl;
}
// 获取文件大小
if (fs::is_regular_file("test.txt")) {
auto size = fs::file_size("test.txt");
std::cout << "File size: " << size << " bytes" << std::endl;
}
// 复制文件
fs::copy_file("source.txt", "destination.txt");
// 删除文件
fs::remove("old_file.txt");
// 创建目录
fs::create_directory("new_folder");
// 遍历目录
for (const auto& entry : fs::directory_iterator(".")) {
std::cout << entry.path() << std::endl;
}
}总结
- ifstream: 用于读取文件
- ofstream: 用于写入文件
- fstream: 用于读写操作
- 使用适当的打开模式
- 始终检查文件操作状态
- 使用 RAII 确保资源正确释放
- C++17 提供了 filesystem 库用于文件系统操作