C++ —— 文件操作(流式操作)
- ofstream
- 文件创建
- 文件写入
- ofstream 文件打开模式
- std::ios::out 写入模式
- std::ios::app 追加模式
- std::ios::trunc 截断
- std::ios::binary 二进制
- std::ios::ate at the end模式
- ifstream
- std::ios::in 读取模式(默认)
- std::ios::binary
- 模式组合
- 常见组合
- 特殊模式说明
- std::ios::ate (At End)
- 重要注意事项
- 完整示例
- 模式总结表
- fstream
- C++ `fstream` 文件流详解
- 基本用法
- 1. 头文件
- 2. 打开文件
- 3. 检查文件是否成功打开
- 文件打开模式
- 读写操作
- 写入文件
- 读取文件
- 二进制读写
- 文件指针控制
- 获取当前位置
- 移动指针
- 完整示例
- 注意事项
- 文件流的成员函数
- **1. 打开/关闭文件**
- **2. 状态检查**
- **3. 读写操作**
- **基本读写**
- **二进制读写**
- **4. 文件指针操作**
- **5. 其他功能**
- **示例代码**
- **注意事项**
- 流式文件操作和一般的文件操作函数区别
- **1. 设计理念**
- **2. 使用方式对比**
- **(1)打开文件**
- **(2)读写数据**
- **(3)关闭文件**
- **3. 核心区别**
- **4. 适用场景**
- **优先使用流式操作的情况**
- **优先使用一般函数的情况**
- **5. 代码示例对比**
- **示例 1:复制文本文件**
- **示例 2:读取二进制数据**
- **总结**
我们之前已经了解过了C语言的文件操作,如果大家对着一块不是很了解的话,可以点击这里:
https://blog.csdn.net/qq_67693066/article/details/135588933?spm=1011.2415.3001.5331
我们来看看C++对于文件操作是怎么办的:
ofstream
ofstream(Output File Stream)是 C++ 中用于写入文件的类,属于 fstream 库。
文件创建
int main()
{std::ofstream file("myfile.txt");//检查是否创建成功// 检查是否创建成功if (!file) {std::cout << "文件创建失败!";return 1;}std::cout << "文件创建成功!";return 0;
}
运行成功的话,可以在项目的路径下看见新创建的文件:
文件写入
ofstream的写入直接用 << 就可以了:
int main()
{std::ofstream file("myfile.txt");if (file) {file << "姓名: 张三\n"; // 写入字符串file << "年龄: " << 25 << "\n"; // 混合写入file << "身高: " << 175.5 << "cm\n";}return 0;
}
ofstream 文件打开模式
ofstream 提供了多种文件打开模式,通过位掩码(std::ios 中的枚举)组合使用:
std::ios::out 写入模式
std::ios::out,文件存在时会清空文件内容,文件不存在的话会创建新的文件,我们可以来试验一下,我刚刚在前面的介绍中往文件中写入了一些文字:
我们重新执行一次代码:
int main()
{std::ofstream file("myfile.txt",std::ios::out); //默认模式return 0;
}
std::ios::app 追加模式
std::ios::app允许你在创建完文件之后,之后再次往文件当中追加内容:
int main()
{//std::ofstream file("myfile.txt",std::ios::out); //默认模式std::ofstream file("myfile.txt", std::ios::app);if (file){file << "I am wiriting\n";}return 0;
}
std::ios::trunc 截断
如果文件已存在,清空文件内容(与 ios::out 默认行为相同)
int main()
{//std::ofstream file("myfile.txt",std::ios::out); //默认模式//std::ofstream file("myfile.txt", std::ios::app);std::ofstream file("myfile.txt", std::ios::trunc);return 0;
}
std::ios::binary 二进制
std::ios::binary 是 C++ 文件流的一个打开模式,用于以二进制形式读写文件,避免文本模式下的字符转换:
适用场景:
- 读写非文本文件(如图片、音频、视频、压缩包等)。
- 精确控制文件内容,避免文本模式下的自动转换。
int main()
{// 以二进制模式写入文件(如果文件存在,会被覆盖)std::ofstream file("data.bin", std::ios::binary | std::ios::out);if (!file) {std::cerr << "Failed to open file!" << std::endl;return 1;}int num = 12345;double pi = 3.14159;char str[] = "Hello Binary!";// 直接写入二进制数据file.write(reinterpret_cast<const char*>(&num), sizeof(num));file.write(reinterpret_cast<const char*>(&pi), sizeof(pi));file.write(str, sizeof(str)); // 包括 '\0' 结束符file.close();std::cout << "Binary data written to data.bin" << std::endl;}
std::ios::ate at the end模式
std::ios::ate 创建之后文件指针的位置就会放在最后,并且可以通过seekp来移动文件指针位置,重新输入内容:
int main()
{std::ofstream file("myfile.txt", std::ios::ate);file << "I am writing " << endl;file.seekp(3);file << "This is a another setence " << endl;return 0;
}
ifstream
std::ifstream 是 C++ 标准库中专门用于从文件读取数据的输入流类,继承自 std::istream。它是文件操作三大类之一(另外两个是 ofstream 和 fstream)。
std::ios::in 读取模式(默认)
std::ios::in 以读取模式打开,文件必须存在,否则会失败:
#include<fstream>int main()
{std::ofstream file1("myfile.txt", std::ios::ate);file1 << "I am writing " << endl;file1.seekp(3);file1 << "This is a another setence " << endl;std::ifstream file2("myfile.txt", std::ios::in);//获取文件大小file2.seekg(0, std::ios::end);std::streampos fileSize = file2.tellg();file2.seekg(0);std::cout << "文件大小: " << fileSize << " 字节" << std::endl;char* buffer = new char[1024*1024]; file2.read(buffer, fileSize);buffer[fileSize] = '\0'; // 添加终止符printf("%s\n", buffer);return 0;
}
std::ios::binary
- 作用:以二进制模式打开文件
- 特点:
- 避免文本模式下的字符转换(如换行符转换)
- 适合读取非文本文件(如图片、视频等)
- 示例:
std::ifstream binFile("image.jpg", std::ios::binary);
模式组合
可以组合多个模式使用,使用按位或运算符 |
:
常见组合
-
普通文本读取:
std::ifstream textFile("text.txt", std::ios::in);
-
二进制读取:
std::ifstream binFile("data.bin", std::ios::in | std::ios::binary);
-
从文件末尾开始读取:
std::ifstream file("log.txt", std::ios::in | std::ios::ate);
特殊模式说明
std::ios::ate (At End)
- 作用:打开文件后立即定位到文件末尾
- 特点:
- 可以先用
tellg()
获取文件大小 - 之后可以用
seekg()
移动到任意位置读取
- 可以先用
- 示例:
std::ifstream file("data.txt", std::ios::in | std::ios::ate); if (file.is_open()) {std::streampos size = file.tellg(); // 获取文件大小file.seekg(0); // 回到文件开头开始读取// ...读取操作... }
重要注意事项
-
文件不存在:
- 如果文件不存在且只使用
std::ios::in
,打开会失败 - 检查是否成功打开:
if (!file.is_open()) {// 处理错误 }
- 如果文件不存在且只使用
-
模式兼容性:
ifstream
不支持写入模式(如std::ios::out
)- 如果需要写入,应使用
fstream
-
二进制模式:
- 在Windows平台上,文本模式会自动转换
\r\n
为\n
- 二进制模式保持原始字节不变
- 在Windows平台上,文本模式会自动转换
-
默认行为:
- 如果不指定任何模式,默认是
std::ios::in
- 如果不指定二进制模式,默认是文本模式
- 如果不指定任何模式,默认是
完整示例
#include <fstream>
#include <iostream>int main() {// 以二进制模式打开文件并从末尾开始std::ifstream file("data.dat", std::ios::in | std::ios::binary | std::ios::ate);if (!file.is_open()) {std::cerr << "无法打开文件" << std::endl;return 1;}// 获取文件大小std::streampos fileSize = file.tellg();std::cout << "文件大小: " << fileSize << " 字节" << std::endl;// 回到文件开头file.seekg(0, std::ios::beg);// 读取文件内容char* buffer = new char[fileSize];file.read(buffer, fileSize);// 处理数据...delete[] buffer;file.close();return 0;
}
模式总结表
模式标志 | 描述 | 适用场景 |
---|---|---|
std::ios::in | 读取模式(默认) | 普通文本文件读取 |
std::ios::binary | 二进制模式 | 非文本文件读取 |
std::ios::ate | 打开后定位到文件末尾 | 需要先获取文件大小的场景 |
fstream
fstream其实是ofstream和ifstream的结合:
C++ fstream
文件流详解
fstream
是 C++ 标准库中用于文件输入输出的流类,它结合了 ifstream
(输入)和 ofstream
(输出)的功能,允许对文件进行读写操作。
基本用法
1. 头文件
#include <fstream>
2. 打开文件
std::fstream file;
file.open("example.txt", std::ios::in | std::ios::out);
或者直接初始化:
std::fstream file("example.txt", std::ios::in | std::ios::out);
3. 检查文件是否成功打开
if (!file.is_open()) {std::cerr << "无法打开文件" << std::endl;return 1;
}
文件打开模式
fstream
支持多种打开模式,可以用位或运算符 |
组合:
模式标志 | 描述 |
---|---|
std::ios::in | 读取模式(文件必须存在) |
std::ios::out | 写入模式(创建或覆盖文件) |
std::ios::app | 追加模式(所有写入在文件末尾) |
std::ios::ate | 打开后定位到文件末尾 |
std::ios::binary | 二进制模式(避免字符转换) |
std::ios::trunc | 如果文件存在,先清空内容 |
读写操作
写入文件
file << "写入一行文本\n";
file << "数字: " << 42 << std::endl;
读取文件
std::string line;
while (std::getline(file, line)) {std::cout << line << std::endl;
}
二进制读写
// 写入二进制数据
int data = 12345;
file.write(reinterpret_cast<char*>(&data), sizeof(data));// 读取二进制数据
int readData;
file.read(reinterpret_cast<char*>(&readData), sizeof(readData));
文件指针控制
获取当前位置
std::streampos pos = file.tellg(); // 获取读取位置
pos = file.tellp(); // 获取写入位置
移动指针
file.seekg(0, std::ios::beg); // 将读取指针移动到文件开头
file.seekp(10, std::ios::cur); // 将写入指针从当前位置移动10字节
完整示例
#include <fstream>
#include <iostream>
#include <string>int main() {// 打开文件用于读写(不存在则创建)std::fstream file("data.txt", std::ios::in | std::ios::out | std::ios::trunc);if (!file.is_open()) {std::cerr << "无法打开文件" << std::endl;return 1;}// 写入数据file << "第一行\n";file << "第二行\n";file << 123 << " " << 3.14 << std::endl;// 回到文件开头读取file.seekg(0);std::string line;while (std::getline(file, line)) {std::cout << "读取到: " << line << std::endl;}file.close();return 0;
}
注意事项
- 模式组合:
fstream
没有默认模式,必须显式指定in
或out
- 文件存在性:使用
in
模式时文件必须存在 - 二进制模式:处理非文本文件时应使用
binary
模式 - 指针同步:读写切换时需要调用
seekg()
或seekp()
- 内存管理:使用
write()
写入二进制数据时要注意数据对齐
fstream
提供了灵活的文件操作能力,适合需要同时读写文件的场景。对于简单的只读或只写操作,可以考虑使用 ifstream
或 ofstream
。
文件流的成员函数
在 C++ 中,文件流相关的类(如 ifstream
, ofstream
, fstream
)提供了许多成员函数来操作文件。以下是常见的文件流成员函数分类说明:
1. 打开/关闭文件
-
open()
打开文件,与流关联。void open(const char* filename, ios_base::openmode mode = ios_base::in | ios_base::out);
filename
:文件路径mode
:打开模式(如ios::in
,ios::out
,ios::binary
,ios::app
等)。
-
close()
关闭文件,释放资源。void close();
2. 状态检查
-
is_open()
检查文件是否成功打开。bool is_open() const;
-
good()
/eof()
/fail()
/bad()
检查流状态:good()
:操作是否正常(无错误)。eof()
:是否到达文件末尾(End-of-File)。fail()
:操作是否失败(可恢复错误,如类型不匹配)。bad()
:是否发生严重错误(如文件损坏)。
3. 读写操作
基本读写
-
>>
(提取运算符)
从文件读取数据(格式化输入)。ifstream file("input.txt"); int value; file >> value; // 读取一个整数
-
<<
(插入运算符)
向文件写入数据(格式化输出)。ofstream file("output.txt"); file << "Hello, World!" << endl;
二进制读写
-
read()
从文件读取二进制数据。istream& read(char* buffer, streamsize size);
buffer
:存储数据的缓冲区。size
:要读取的字节数。
-
write()
向文件写入二进制数据。ostream& write(const char* buffer, streamsize size);
4. 文件指针操作
-
tellg()
/tellp()
获取当前读写位置:tellg()
:返回输入流(读)的指针位置(ifstream
)。tellp()
:返回输出流(写)的指针位置(ofstream
)。
-
seekg()
/seekp()
移动文件指针:istream& seekg(streampos pos); // 移动到绝对位置 istream& seekg(streamoff offset, ios_base::seekdir dir); // 相对位置移动
pos
:绝对位置。offset
:偏移量。dir
:基准位置(ios::beg
开头,ios::cur
当前位置,ios::end
结尾)。
5. 其他功能
-
flush()
强制刷新输出缓冲区(立即写入文件)。ostream& flush();
-
peek()
查看下一个字符但不移动指针。int peek();
-
get()
/getline()
读取字符或一行:int get(); // 读取单个字符 istream& getline(char* buffer, streamsize size); // 读取一行
示例代码
#include <fstream>
#include <iostream>
using namespace std;int main() {// 写入文件ofstream out("test.txt");if (out.is_open()) {out << "Line 1\nLine 2" << endl;out.close();}// 读取文件ifstream in("test.txt");if (in.is_open()) {string line;while (getline(in, line)) {cout << line << endl;}in.close();}return 0;
}
注意事项
- 模式标志:
ios::in
(读)、ios::out
(写)、ios::binary
(二进制)、ios::app
(追加)等可组合使用。
- 错误处理:
始终检查is_open()
或good()
避免未定义行为。 - 资源释放:
显式调用close()
或依赖析构函数自动关闭。
根据需求选择合适的函数组合即可高效操作文件!
流式文件操作和一般的文件操作函数区别
在 C++ 中,流式文件操作(基于 fstream
/ifstream
/ofstream
)和 一般文件操作函数(基于 C 语言的 FILE*
或系统 API)是两种不同的文件处理方式,它们在设计理念、使用方式和适用场景上有显著区别。以下是详细对比:
1. 设计理念
特性 | 流式文件操作 (fstream 等) | 一般文件操作函数 (fopen /read /Write 等) |
---|---|---|
封装层次 | 高级封装,面向对象(基于 std::iostream 类体系) | 低级封装,面向过程(函数调用) |
数据视角 | 将文件视为连续的字符流或对象序列 | 将文件视为字节块或二进制数据 |
缓冲区管理 | 自动缓冲(默认),支持手动刷新 (flush ) | 需手动管理缓冲区(如 setvbuf ) |
错误处理 | 通过流状态标志(good() , fail() )或异常机制 | 通过返回值(如 NULL 或 -1 )和全局 errno |
2. 使用方式对比
(1)打开文件
- 流式操作:
#include <fstream> std::ifstream fin("input.txt", std::ios::binary); // 二进制模式 std::ofstream fout("output.txt");
- 一般函数:
#include <cstdio> FILE* fin = fopen("input.txt", "rb"); // C 风格 int fd = open("input.txt", O_RDONLY); // POSIX API
(2)读写数据
- 流式操作(类型安全):
int num; fin >> num; // 格式化读取(文本) fout << "Hello" << std::endl; // 格式化写入fin.read(buffer, size); // 二进制读取 fout.write(buffer, size); // 二进制写入
- 一般函数(直接操作字节):
fscanf(fin, "%d", &num); // C 格式化读取 fprintf(fout, "Hello\n");fread(buffer, 1, size, fin); // C 二进制读取 write(fd, buffer, size); // POSIX 写入
(3)关闭文件
- 流式操作(自动析构):
fin.close(); // 可省略,析构时自动调用
- 一般函数(需显式关闭):
fclose(fin); // C 风格 close(fd); // POSIX
3. 核心区别
对比项 | 流式文件操作 | 一般文件操作函数 |
---|---|---|
类型安全 | ✅ 支持运算符重载(<< />> ),避免类型错误 | ❌ 需手动匹配格式字符串(如 %d vs %f ) |
性能 | ⚠️ 默认有缓冲,适合高频小数据量操作 | ⚠️ 无缓冲时更快,适合大块二进制数据 |
灵活性 | ❌ 高级封装,底层控制受限(如精确指针移动) | ✅ 直接操作文件描述符/指针,控制更精细 |
跨平台性 | ✅ 标准 C++ 实现,跨平台一致 | ⚠️ C 库跨平台,但系统 API(如 open )需适配 |
异常支持 | ✅ 可通过 exceptions() 启用异常 | ❌ 仅通过返回值/errno 处理错误 |
4. 适用场景
优先使用流式操作的情况
- 需要 类型安全 的文本读写(如配置文件、日志)。
- 代码已基于 C++ 标准库,希望保持风格统一。
- 简单的逐行或格式化数据处理(如
getline
读取 CSV)。
优先使用一般函数的情况
- 需要 高性能二进制操作(如大文件拷贝、网络数据传输)。
- 依赖 系统特定功能(如文件锁、内存映射)。
- 遗留项目或与 C 语言交互的代码。
5. 代码示例对比
示例 1:复制文本文件
- 流式操作:
std::ifstream src("source.txt"); std::ofstream dst("dest.txt"); dst << src.rdbuf(); // 一行完成拷贝
- 一般函数:
FILE* src = fopen("source.txt", "r"); FILE* dst = fopen("dest.txt", "w"); char buffer[4096]; while (size_t len = fread(buffer, 1, sizeof(buffer), src)) {fwrite(buffer, 1, len, dst); } fclose(src); fclose(dst);
示例 2:读取二进制数据
- 流式操作:
std::ifstream file("data.bin", std::ios::binary); int value; file.read(reinterpret_cast<char*>(&value), sizeof(value));
- 一般函数:
FILE* file = fopen("data.bin", "rb"); int value; fread(&value, sizeof(value), 1, file);
总结
- 流式操作:适合 高层抽象、类型安全 的场景,代码简洁但灵活性较低。
- 一般函数:适合 底层控制、高性能二进制处理,但需手动管理资源。
根据项目需求选择合适的方式,现代 C++ 项目推荐优先使用 <fstream>
,除非有明确的性能或控制需求。