跳到主要内容

C++ 写入文件

在C++编程中,向文件写入数据是一项非常实用的技能。无论是保存程序运行结果、创建日志文件,还是生成数据报告,文件写入操作都扮演着重要角色。本教程将全面介绍C++中如何向文件写入数据。

文件输出概述

在C++中,文件输出是通过ofstream类实现的,它是从ostream类派生出来的,专门用于向文件写入数据。ofstream类定义在<fstream>头文件中。

要向文件写入数据,通常需要遵循以下步骤:

  1. 包含必要的头文件
  2. 创建一个ofstream对象
  3. 打开文件
  4. 检查文件是否成功打开
  5. 写入数据
  6. 关闭文件

基本文件写入

下面是一个简单的文件写入示例:

cpp
#include <iostream>
#include <fstream>
using namespace std;

int main() {
// 创建ofstream对象
ofstream outFile;

// 打开文件,如果不存在会创建新文件
outFile.open("example.txt");

// 检查文件是否成功打开
if (!outFile) {
cerr << "无法打开文件!" << endl;
return 1;
}

// 向文件写入数据
outFile << "这是写入文件的第一行。" << endl;
outFile << "这是第二行。" << endl;
outFile << "数字示例: " << 42 << endl;

// 关闭文件
outFile.close();

cout << "数据已成功写入文件!" << endl;
return 0;
}

输出:

数据已成功写入文件!

文件 example.txt 的内容:

这是写入文件的第一行。
这是第二行。
数字示例: 42
提示

也可以在创建ofstream对象的同时打开文件:

cpp
ofstream outFile("example.txt");

文件打开模式

在打开文件时,我们可以指定不同的打开模式来控制文件的写入行为:

cpp
outFile.open("example.txt", ios::out | ios::app);

常用的文件打开模式包括:

模式描述
ios::out输出模式(默认)。如果文件已存在,其内容会被清空
ios::app追加模式。新内容添加到文件末尾
ios::trunc如果文件存在,删除文件内容(默认与ios::out一起使用)
ios::binary二进制模式

追加到文件

如果我们想要在不删除现有内容的情况下向文件添加新内容,可以使用追加模式:

cpp
#include <iostream>
#include <fstream>
using namespace std;

int main() {
// 打开文件用于追加
ofstream outFile("example.txt", ios::app);

if (!outFile) {
cerr << "无法打开文件!" << endl;
return 1;
}

// 向文件追加数据
outFile << "这是追加的一行。" << endl;
outFile.close();

cout << "数据已成功追加到文件!" << endl;
return 0;
}

格式化文件输出

和标准输出流一样,我们可以使用操纵符来格式化文件输出:

cpp
#include <iostream>
#include <fstream>
#include <iomanip> // 用于格式化操纵符
using namespace std;

int main() {
ofstream outFile("format.txt");

if (!outFile) {
cerr << "无法打开文件!" << endl;
return 1;
}

// 写入格式化数据
outFile << setprecision(2) << fixed; // 设置浮点数精度为2位小数
outFile << "价格: " << setw(10) << right << 10.5 << endl;
outFile << "折扣: " << setw(10) << right << 0.25 << endl;
outFile << "总计: " << setw(10) << right << 7.875 << endl;

outFile.close();
cout << "格式化数据已写入文件!" << endl;
return 0;
}

文件 format.txt 的内容:

价格:      10.50
折扣: 0.25
总计: 7.88

二进制文件写入

文本文件适合存储人类可读的信息,而二进制文件更适合存储复杂的数据结构或需要精确表示的数值数据。使用write()函数可以写入二进制数据:

cpp
#include <iostream>
#include <fstream>
using namespace std;

struct Person {
char name[50];
int age;
double salary;
};

int main() {
Person person = {"张三", 25, 5000.75};

// 打开二进制文件用于写入
ofstream outFile("person.dat", ios::binary);

if (!outFile) {
cerr << "无法打开文件!" << endl;
return 1;
}

// 写入二进制数据
outFile.write(reinterpret_cast<char*>(&person), sizeof(Person));

outFile.close();
cout << "二进制数据已写入文件!" << endl;
return 0;
}
警告

二进制文件的内容不是人类可读的,需要使用相应的方法读取。

写多个对象到文件

我们可以写入多个对象或数组数据到文件中:

cpp
#include <iostream>
#include <fstream>
using namespace std;

struct Student {
int id;
char name[30];
double gpa;
};

int main() {
Student students[3] = {
{1001, "李明", 3.75},
{1002, "王华", 3.89},
{1003, "赵芳", 3.65}
};

ofstream outFile("students.dat", ios::binary);

if (!outFile) {
cerr << "无法打开文件!" << endl;
return 1;
}

// 写入学生数组
for (int i = 0; i < 3; i++) {
outFile.write(reinterpret_cast<char*>(&students[i]), sizeof(Student));
}

outFile.close();
cout << "所有学生数据已写入文件!" << endl;
return 0;
}

检测和处理文件写入错误

在实际应用中,我们需要检测并妥善处理文件写入过程中可能出现的错误:

cpp
#include <iostream>
#include <fstream>
using namespace std;

int main() {
ofstream outFile("data.txt");

if (!outFile) {
cerr << "无法打开文件!" << endl;
return 1;
}

// 写入数据
outFile << "测试数据" << endl;

// 检查是否发生错误
if (outFile.fail()) {
cerr << "写入文件时发生错误!" << endl;
outFile.close();
return 1;
}

outFile.close();

// 检查关闭是否成功
if (outFile.fail()) {
cerr << "关闭文件时发生错误!" << endl;
return 1;
}

cout << "文件操作成功!" << endl;
return 0;
}

实际应用案例:创建日志文件

下面是一个更加实用的示例,展示如何创建一个简单的日志文件:

cpp
#include <iostream>
#include <fstream>
#include <ctime>
#include <string>
using namespace std;

// 日志级别枚举
enum LogLevel {
INFO,
WARNING,
ERROR
};

// 添加日志条目的函数
void logMessage(ofstream &logFile, LogLevel level, const string &message) {
// 获取当前时间
time_t now = time(0);
char timeStr[26];
ctime_s(timeStr, sizeof(timeStr), &now);
string time(timeStr);
time = time.substr(0, time.length() - 1); // 移除换行符

// 确定日志级别字符串
string levelStr;
switch (level) {
case INFO:
levelStr = "信息";
break;
case WARNING:
levelStr = "警告";
break;
case ERROR:
levelStr = "错误";
break;
}

// 写入日志
logFile << "[" << time << "] [" << levelStr << "] " << message << endl;
}

int main() {
// 打开日志文件(追加模式)
ofstream logFile("application.log", ios::app);

if (!logFile) {
cerr << "无法打开日志文件!" << endl;
return 1;
}

// 添加一些日志条目
logMessage(logFile, INFO, "应用程序启动");
logMessage(logFile, INFO, "初始化完成");
logMessage(logFile, WARNING, "配置文件缺少可选参数");
logMessage(logFile, INFO, "开始处理数据");
logMessage(logFile, ERROR, "数据处理过程中遇到错误: 无效输入");
logMessage(logFile, INFO, "应用程序关闭");

logFile.close();
cout << "日志已更新!" << endl;
return 0;
}

文件 application.log 的部分内容:

[Mon Oct 16 14:32:47 2023] [信息] 应用程序启动
[Mon Oct 16 14:32:47 2023] [信息] 初始化完成
[Mon Oct 16 14:32:47 2023] [警告] 配置文件缺少可选参数
[Mon Oct 16 14:32:47 2023] [信息] 开始处理数据
[Mon Oct 16 14:32:47 2023] [错误] 数据处理过程中遇到错误: 无效输入
[Mon Oct 16 14:32:47 2023] [信息] 应用程序关闭

总结

本教程详细介绍了C++中的文件写入操作:

  • 使用ofstream对象向文件写入数据
  • 不同的文件打开模式(普通、追加、二进制等)
  • 文本文件和二进制文件的写入方法
  • 格式化文件输出
  • 错误检测和处理
  • 实际应用案例(日志文件创建)

掌握文件写入技能将使你能够创建持久化数据、生成报告和记录程序运行信息,这是构建更复杂C++应用程序的重要基础。

练习

  1. 创建一个程序,让用户输入学生信息(姓名、ID、成绩),然后将这些信息写入文本文件。
  2. 修改上面的程序,让它能够将学生信息以二进制格式写入文件。
  3. 实现一个简单的文本编辑器,允许用户输入多行文本并将其保存到文件中。
  4. 创建一个程序,生成一个包含随机数的数据文件,并确保数字按照表格形式排列。
  5. 扩展日志系统,添加不同的日志文件级别,并允许配置要写入的最低日志级别。

扩展阅读

  • 文件流缓冲区及其影响
  • 文件锁定机制
  • 使用临时文件
  • 处理大文件写入的性能优化