目录
基础概念
文件类型
- 文本文件:以ASCII码形式存储数据
- 二进制文件:以二进制形式存储数据
文件模式
// ios::in - 读取模式
// ios::out - 写入模式
// ios::app - 追加模式
// ios::ate - 打开后定位到文件末尾
// ios::trunc - 截断文件(清空内容)
// ios::binary - 二进制模式
文件流基础
三种文件流类
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
// 1. ofstream - 输出文件流(写文件)
ofstream outFile;
// 2. ifstream - 输入文件流(读文件)
ifstream inFile;
// 3. fstream - 文件流(读写文件)
fstream file;
return 0;
}
文件读写操作
1. 文本文件写入
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
// 基础写入操作
void basicWrite() {
ofstream file("example.txt");
if (file.is_open()) {
file << "Hello, World!" << endl;
file << "This is a test file." << endl;
file << "Number: " << 42 << endl;
file.close();
cout << "文件写入成功!" << endl;
} else {
cout << "无法打开文件!" << endl;
}
}
// 向量数据写入
void vectorWrite() {
vector<string> data = {
"第一行数据",
"第二行数据",
"第三行数据"
};
ofstream file("vector_data.txt");
if (file.is_open()) {
for (const auto& line : data) {
file << line << endl;
}
file.close();
cout << "向量数据写入完成!" << endl;
}
}
// 追加模式写入
void appendWrite() {
ofstream file("example.txt", ios::app);
if (file.is_open()) {
file << "追加的内容" << endl;
file.close();
cout << "追加写入完成!" << endl;
}
}
2. 文本文件读取
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
// 逐行读取
void readLineByLine() {
ifstream file("example.txt");
string line;
if (file.is_open()) {
cout << "文件内容:" << endl;
while (getline(file, line)) {
cout << line << endl;
}
file.close();
} else {
cout << "无法打开文件!" << endl;
}
}
// 逐词读取
void readWordByWord() {
ifstream file("example.txt");
string word;
if (file.is_open()) {
cout << "逐词读取:" << endl;
while (file >> word) {
cout << word << " ";
}
cout << endl;
file.close();
}
}
// 全部读取到字符串
void readAll() {
ifstream file("example.txt");
string content((istreambuf_iterator<char>(file)),
istreambuf_iterator<char>());
if (!content.empty()) {
cout << "全部内容:" << endl;
cout << content << endl;
}
file.close();
}
// 读取到向量
vector<string> readToVector() {
vector<string> lines;
ifstream file("example.txt");
string line;
while (getline(file, line)) {
lines.push_back(line);
}
file.close();
return lines;
}
文件定位和状态
文件指针操作
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void filePositionDemo() {
fstream file("position_demo.txt", ios::in | ios::out | ios::trunc);
if (file.is_open()) {
// 写入初始数据
file << "0123456789" << endl;
file << "abcdefghij" << endl;
// 获取当前位置
streampos currentPos = file.tellp();
cout << "当前位置:" << currentPos << endl;
// 移动到文件开头
file.seekp(0, ios::beg);
file << "ABC";
// 移动到文件末尾
file.seekp(0, ios::end);
file << "END";
// 移动到相对位置
file.seekp(-3, ios::cur);
file << "XYZ";
file.close();
}
}
// 检查文件状态
void checkFileStatus() {
ifstream file("test.txt");
cout << "文件状态检查:" << endl;
cout << "is_open(): " << file.is_open() << endl;
cout << "good(): " << file.good() << endl;
cout << "eof(): " << file.eof() << endl;
cout << "fail(): " << file.fail() << endl;
cout << "bad(): " << file.bad() << endl;
file.close();
}
二进制文件处理
二进制文件读写
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
using namespace std;
// 学生结构体
struct Student {
int id;
char name[50];
double score;
Student() : id(0), score(0.0) {
strcpy(name, "");
}
Student(int i, const char* n, double s) : id(i), score(s) {
strncpy(name, n, 49);
name[49] = '\0';
}
};
// 写入二进制文件
void writeBinaryFile() {
vector<Student> students = {
Student(1, "张三", 85.5),
Student(2, "李四", 92.0),
Student(3, "王五", 78.5)
};
ofstream file("students.dat", ios::binary);
if (file.is_open()) {
for (const auto& student : students) {
file.write(reinterpret_cast<const char*>(&student), sizeof(Student));
}
file.close();
cout << "二进制文件写入完成!" << endl;
}
}
// 读取二进制文件
void readBinaryFile() {
ifstream file("students.dat", ios::binary);
if (file.is_open()) {
Student student;
cout << "学生信息:" << endl;
while (file.read(reinterpret_cast<char*>(&student), sizeof(Student))) {
cout << "ID: " << student.id
<< ", 姓名: " << student.name
<< ", 分数: " << student.score << endl;
}
file.close();
}
}
// 随机访问二进制文件
void randomAccessBinary() {
fstream file("students.dat", ios::in | ios::out | ios::binary);
if (file.is_open()) {
Student student;
// 读取第二个学生
file.seekg(sizeof(Student), ios::beg);
file.read(reinterpret_cast<char*>(&student), sizeof(Student));
cout << "第二个学生: " << student.name << endl;
// 修改第三个学生
Student newStudent(3, "赵六", 95.0);
file.seekp(2 * sizeof(Student), ios::beg);
file.write(reinterpret_cast<const char*>(&newStudent), sizeof(Student));
file.close();
}
}
高级文件操作
CSV文件处理
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
class CSVReader {
private:
string filename;
public:
CSVReader(const string& fname) : filename(fname) {}
vector<vector<string>> readCSV() {
vector<vector<string>> data;
ifstream file(filename);
if (!file.is_open()) {
cerr << "无法打开文件: " << filename << endl;
return data;
}
string line;
while (getline(file, line)) {
vector<string> row;
stringstream ss(line);
string cell;
while (getline(ss, cell, ',')) {
row.push_back(cell);
}
data.push_back(row);
}
file.close();
return data;
}
void writeCSV(const vector<vector<string>>& data) {
ofstream file(filename);
if (!file.is_open()) {
cerr << "无法创建文件: " << filename << endl;
return;
}
for (const auto& row : data) {
for (size_t i = 0; i < row.size(); ++i) {
file << row[i];
if (i < row.size() - 1) {
file << ",";
}
}
file << endl;
}
file.close();
}
};
// 使用示例
void csvExample() {
// 创建示例数据
vector<vector<string>> data = {
{"姓名", "年龄", "城市"},
{"张三", "25", "北京"},
{"李四", "30", "上海"},
{"王五", "28", "广州"}
};
// 写入CSV文件
CSVReader writer("data.csv");
writer.writeCSV(data);
// 读取CSV文件
CSVReader reader("data.csv");
auto readData = reader.readCSV();
cout << "读取的CSV数据:" << endl;
for (const auto& row : readData) {
for (const auto& cell : row) {
cout << cell << "\t";
}
cout << endl;
}
}
配置文件处理
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
class ConfigFile {
private:
map<string, string> config;
string filename;
// 去除字符串两端空格
string trim(const string& str) {
size_t first = str.find_first_not_of(' ');
if (first == string::npos) return "";
size_t last = str.find_last_not_of(' ');
return str.substr(first, (last - first + 1));
}
public:
ConfigFile(const string& fname) : filename(fname) {
load();
}
// 加载配置文件
void load() {
ifstream file(filename);
if (!file.is_open()) return;
string line;
while (getline(file, line)) {
// 跳过注释和空行
if (line.empty() || line[0] == '#' || line[0] == ';') continue;
// 查找等号
size_t pos = line.find('=');
if (pos != string::npos) {
string key = trim(line.substr(0, pos));
string value = trim(line.substr(pos + 1));
config[key] = value;
}
}
file.close();
}
// 保存配置文件
void save() {
ofstream file(filename);
if (!file.is_open()) return;
for (const auto& pair : config) {
file << pair.first << " = " << pair.second << endl;
}
file.close();
}
// 设置配置项
void set(const string& key, const string& value) {
config[key] = value;
}
// 获取配置项
string get(const string& key, const string& defaultValue = "") {
auto it = config.find(key);
return (it != config.end()) ? it->second : defaultValue;
}
// 获取整数配置
int getInt(const string& key, int defaultValue = 0) {
string value = get(key);
if (!value.empty()) {
try {
return stoi(value);
} catch (...) {
return defaultValue;
}
}
return defaultValue;
}
// 获取浮点数配置
double getDouble(const string& key, double defaultValue = 0.0) {
string value = get(key);
if (!value.empty()) {
try {
return stod(value);
} catch (...) {
return defaultValue;
}
}
return defaultValue;
}
// 检查键是否存在
bool exists(const string& key) {
return config.find(key) != config.end();
}
// 删除配置项
void remove(const string& key) {
config.erase(key);
}
// 显示所有配置
void display() {
cout << "配置文件内容:" << endl;
for (const auto& pair : config) {
cout << pair.first << " = " << pair.second << endl;
}
}
};
// 使用示例
void configFileExample() {
// 创建配置文件
{
ofstream file("config.ini");
file << "# 配置文件示例\n";
file << "server_ip = 192.168.1.100\n";
file << "port = 8080\n";
file << "timeout = 30.5\n";
file << "debug = true\n";
file.close();
}
// 使用配置文件类
ConfigFile config("config.ini");
cout << "服务器IP: " << config.get("server_ip") << endl;
cout << "端口: " << config.getInt("port") << endl;
cout << "超时时间: " << config.getDouble("timeout") << endl;
cout << "调试模式: " << config.get("debug") << endl;
// 修改配置
config.set("server_ip", "192.168.1.200");
config.set("max_connections", "100");
// 保存配置
config.save();
// 显示所有配置
config.display();
}
实用工具类
文件操作工具类
#include <iostream>
#include <fstream>
#include <filesystem>
#include <vector>
#include <string>
using namespace std;
namespace fs = std::filesystem;
class FileUtils {
public:
// 检查文件是否存在
static bool fileExists(const string& filename) {
return fs::exists(filename);
}
// 获取文件大小
static size_t getFileSize(const string& filename) {
if (!fileExists(filename)) return 0;
return fs::file_size(filename);
}
// 复制文件
static bool copyFile(const string& source, const string& destination) {
try {
fs::copy_file(source, destination, fs::copy_options::overwrite_existing);
return true;
} catch (const fs::filesystem_error& ex) {
cerr << "复制文件失败: " << ex.what() << endl;
return false;
}
}
// 移动文件
static bool moveFile(const string& source, const string& destination) {
try {
fs::rename(source, destination);
return true;
} catch (const fs::filesystem_error& ex) {
cerr << "移动文件失败: " << ex.what() << endl;
return false;
}
}
// 删除文件
static bool deleteFile(const string& filename) {
try {
return fs::remove(filename);
} catch (const fs::filesystem_error& ex) {
cerr << "删除文件失败: " << ex.what() << endl;
return false;
}
}
// 创建目录
static bool createDirectory(const string& path) {
try {
return fs::create_directories(path);
} catch (const fs::filesystem_error& ex) {
cerr << "创建目录失败: " << ex.what() << endl;
return false;
}
}
// 列出目录中的文件
static vector<string> listFiles(const string& directory) {
vector<string> files;
try {
for (const auto& entry : fs::directory_iterator(directory)) {
if (entry.is_regular_file()) {
files.push_back(entry.path().string());
}
}
} catch (const fs::filesystem_error& ex) {
cerr << "列出文件失败: " << ex.what() << endl;
}
return files;
}
// 读取整个文件到字符串
static string readFileToString(const string& filename) {
ifstream file(filename, ios::binary);
if (!file.is_open()) return "";
string content((istreambuf_iterator<char>(file)),
istreambuf_iterator<char>());
file.close();
return content;
}
// 将字符串写入文件
static bool writeStringToFile(const string& filename, const string& content) {
ofstream file(filename, ios::binary);
if (!file.is_open()) return false;
file << content;
file.close();
return true;
}
// 获取文件扩展名
static string getFileExtension(const string& filename) {
size_t pos = filename.find_last_of('.');
if (pos != string::npos) {
return filename.substr(pos + 1);
}
return "";
}
// 获取文件名(不含路径)
static string getFileName(const string& filepath) {
size_t pos = filepath.find_last_of("/\\");
if (pos != string::npos) {
return filepath.substr(pos + 1);
}
return filepath;
}
};
// 使用示例
void fileUtilsExample() {
// 创建测试文件
ofstream testFile("test.txt");
testFile << "这是一个测试文件的内容。" << endl;
testFile.close();
// 测试文件工具类
cout << "文件存在: " << FileUtils::fileExists("test.txt") << endl;
cout << "文件大小: " << FileUtils::getFileSize("test.txt") << " 字节" << endl;
cout << "文件扩展名: " << FileUtils::getFileExtension("test.txt") << endl;
cout << "文件名: " << FileUtils::getFileName("/path/to/test.txt") << endl;
// 复制文件
FileUtils::copyFile("test.txt", "test_copy.txt");
cout << "文件复制完成" << endl;
// 读取文件内容
string content = FileUtils::readFileToString("test.txt");
cout << "文件内容: " << content << endl;
// 清理测试文件
FileUtils::deleteFile("test.txt");
FileUtils::deleteFile("test_copy.txt");
}
错误处理
异常安全的文件操作
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
using namespace std;
class SafeFileHandler {
private:
fstream file;
string filename;
public:
SafeFileHandler(const string& fname) : filename(fname) {}
~SafeFileHandler() {
if (file.is_open()) {
file.close();
}
}
// 安全打开文件
bool open(ios::openmode mode) {
try {
file.open(filename, mode);
if (!file.is_open()) {
throw runtime_error("无法打开文件: " + filename);
}
return true;
} catch (const exception& ex) {
cerr << "文件打开错误: " << ex.what() << endl;
return false;
}
}
// 安全写入
bool write(const string& data) {
try {
if (!file.is_open()) {
throw runtime_error("文件未打开");
}
file << data;
if (file.fail()) {
throw runtime_error("写入失败");
}
return true;
} catch (const exception& ex) {
cerr << "写入错误: " << ex.what() << endl;
return false;
}
}
// 安全读取
bool read(string& data) {
try {
if (!file.is_open()) {
throw runtime_error("文件未打开");
}
data.assign((istreambuf_iterator<char>(file)),
istreambuf_iterator<char>());
if (file.bad()) {
throw runtime_error("读取失败");
}
return true;
} catch (const exception& ex) {
cerr << "读取错误: " << ex.what() << endl;
return false;
}
}
};
// RAII文件操作示例
class FileRAII {
private:
ofstream file;
public:
FileRAII(const string& filename) : file(filename) {
if (!file.is_open()) {
throw runtime_error("无法创建文件: " + filename);
}
}
~FileRAII() {
if (file.is_open()) {
file.close();
}
}
void write(const string& data) {
file << data;
}
};
// 使用示例
void errorHandlingExample() {
try {
// 使用RAII确保文件正确关闭
{
FileRAII file("safe_example.txt");
file.write("安全的文件操作示例");
} // 文件在这里自动关闭
// 使用安全文件处理器
SafeFileHandler handler("safe_example.txt");
if (handler.open(ios::in)) {
string content;
if (handler.read(content)) {
cout << "读取内容: " << content << endl;
}
}
} catch (const exception& ex) {
cerr << "异常: " << ex.what() << endl;
}
}
完整示例程序
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <chrono>
using namespace std;
// 日志文件类
class Logger {
private:
ofstream logFile;
string filename;
public:
Logger(const string& fname) : filename(fname) {
logFile.open(filename, ios::app);
if (!logFile.is_open()) {
cerr << "无法打开日志文件: " << filename << endl;
}
}
~Logger() {
if (logFile.is_open()) {
logFile.close();
}
}
void log(const string& message) {
auto now = chrono::system_clock::now();
auto time_t = chrono::system_clock::to_time_t(now);
if (logFile.is_open()) {
logFile << ctime(&time_t) << ": " << message << endl;
}
}
};
// 主程序示例
int main() {
cout << "=== C++ 文件处理示例 ===" << endl;
// 1. 基础文件操作
basicWrite();
readLineByLine();
// 2. 二进制文件操作
writeBinaryFile();
readBinaryFile();
// 3. CSV文件处理
csvExample();
// 4. 配置文件处理
configFileExample();
// 5. 文件工具类
fileUtilsExample();
// 6. 错误处理
errorHandlingExample();
// 7. 日志记录示例
Logger logger("app.log");
logger.log("应用程序启动");
logger.log("执行文件操作");
logger.log("应用程序关闭");
cout << "所有示例执行完成!" << endl;
return 0;
}
总结
关键要点
-
选择合适的流类:
ofstream用于写文件ifstream用于读文件fstream用于读写文件
-
正确管理资源:
- 使用 RAII 原则
- 确保文件正确关闭
- 处理异常情况
-
模式选择:
- 文本模式 vs 二进制模式
- 读写模式组合
- 追加 vs 截断
-
性能考虑:
- 缓冲区使用
- 批量操作
- 避免频繁的文件打开/关闭
最佳实践
- 始终检查文件操作是否成功
- 使用智能指针或RAII管理文件资源
- 合理使用异常处理
- 选择合适的文件访问模式
- 注意跨平台兼容性
这个教程涵盖了C++文件处理的各个方面,从基础到高级,提供了丰富的代码示例和实用工具类,可以帮助你掌握C++文件处理的各种技巧。