C 文件操作基于标准库fstream以流stream为核心提供面向对象的文件读写能力比 C 语言的FILE*更安全、更灵活。本文从核心类、打开模式、基础操作、文本 / 二进制读写、指针操作、错误处理、高级功能到最佳实践全面覆盖所有关键知识点。C 文件操作速查手册-CSDN博客https://blog.csdn.net/Howrun777/article/details/157380224?spm1011.2415.3001.5331一、核心头文件与类1. 核心头文件#include fstream // 核心文件流类ifstream/ofstream/fstream #include iostream // 基础流cin/cout文件流继承自其基类 #include string // 字符串处理文件路径、读写内容 #include cstdio // 高级操作重命名、删除文件可选2. 三大核心文件流类文件流类继承自标准 I/O 流基类分工明确类名继承关系核心功能适用场景std::ifstreamios_base→ios→istream→ifstream只读文件读取配置文件、日志、文本内容std::ofstreamios_base→ios→ostream→ofstream只写文件写入日志、生成报告、保存数据std::fstreamios_base→ios→iostream→fstream读写文件同时需要读 / 写的场景如修改文件关键ifstream/ofstream是单方向流fstream是双向流可同时读写。二、文件打开模式核心打开文件时需指定打开模式std::ios_base::openmode类型决定文件的操作方式可通过|组合多个模式。1. 常用模式常量模式常量含义适用类std::ios::in以只读方式打开文件不存在则打开失败ifstream默认、fstreamstd::ios::out以只写方式打开文件不存在则创建存在则清空内容默认含truncofstream默认、fstreamstd::ios::app以追加方式写写入内容添加到文件末尾不清空原有内容ofstream、fstreamstd::ios::trunc打开时清空文件原有内容out默认包含此模式ofstream、fstreamstd::ios::binary以二进制模式打开默认是文本模式不处理换行符等特殊字符所有文件流类std::ios::ate打开文件后文件指针直接定位到文件末尾可后续移动指针所有文件流类std::ios::nocreate打开时不创建新文件文件不存在则打开失败部分编译器支持所有文件流类std::ios::noreplace打开时不覆盖已有文件文件存在则打开失败部分编译器支持所有文件流类2. 各流默认模式ifstream默认std::ios::in只读ofstream默认std::ios::out | std::ios::trunc只写 清空fstream默认std::ios::in | std::ios::out读写文件不存在则失败3. 模式组合示例// 1. 只读文本文件ifstream默认可省略模式 std::ifstream in(dict.conf); // 2. 只写追加文本文件不清空原有内容 std::ofstream out(log.txt, std::ios::out | std::ios::app); // 3. 读写二进制文件用于图片、视频等 std::fstream fs(data.bin, std::ios::in | std::ios::out | std::ios::binary); // 4. 只写不创建新文件文件不存在则失败 std::ofstream out(exist.txt, std::ios::out | std::ios::nocreate);std::fstream in(_path);中的in是 **std::fstream类的实例对象 **不是变量、指针或其他类型。这个对象封装了文件读取的所有状态和行为是你操作文件的核心 “载体”。你对文件的所有读取操作检查打开状态、逐行读取、移动指针等本质上都是通过调用in这个对象的成员方法完成的。三、文件操作基本流程无论读 / 写核心流程都是打开文件 → 检查是否成功 → 读写操作 → 关闭文件。1. 打开文件两种方式方式 1构造函数直接打开推荐RAII 风格// 只读打开 std::ifstream in(test.txt); // 只写追加打开 std::ofstream out(log.txt, std::ios::app); // 读写二进制打开 std::fstream fs(data.bin, std::ios::in | std::ios::out | std::ios::binary);方式 2先创建对象再调用open()std::ifstream in; in.open(test.txt, std::ios::in); // 显式指定模式2. 检查文件是否打开成功必须文件打开可能失败路径错误、权限不足、文件不存在等必须先检查std::ifstream in(test.txt); if (!in.is_open()) { // 或直接写 if (!in)流对象可隐式转换为bool std::cerr 文件打开失败路径 test.txt std::endl; return 1; // 异常退出 }3. 关闭文件显式关闭调用close()方法释放文件资源推荐尤其是长时间运行的程序。自动关闭流对象析构时会自动调用close()RAII 特性无需手动关也能释放资源。in.close(); // 显式关闭 out.close(); fs.close();四、文本文件读写最常用文本文件以字符为单位读写默认会处理换行符Windows\r\nLinux\n适合配置文件、日志、纯文本内容。1. 文本读操作ifstream/fstream1逐行读取std::getline最常用适合读取配置文件、日志等按行存储的内容#include iostream #include fstream #include string int main() { std::ifstream in(dict.conf); if (!in) { std::cerr 打开失败 std::endl; return 1; } std::string line; // 逐行读取直到文件末尾getline返回流对象eof时为false while (std::getline(in, line)) { std::cout 读取行 line std::endl; } in.close(); return 0; }2按空白符分割读取运算符会自动跳过空格、换行、制表符等空白符适合读取单词、数字std::ifstream in(num.txt); // 内容10 20 30 40 int num; while (in num) { // 每次读取一个整数 std::cout 读取数字 num std::endl; } // 输出10 20 30 403单字符读取get()读取单个字符包括空白符、换行符适合逐字符处理std::ifstream in(test.txt); char ch; while (in.get(ch)) { // 读取单个字符 std::cout ch; // 原样输出所有字符包括换行、空格 }2. 文本写操作ofstream/fstream1格式化写入运算符和std::cout用法一致支持格式化输出如整数、字符串、浮点数#include iostream #include fstream #include string int main() { // 只写追加打开不清空原有内容 std::ofstream out(log.txt, std::ios::app); if (!out) { std::cerr 打开失败 std::endl; return 1; } // 写入字符串 out 程序启动时间2026-01-26 10:00:00 std::endl; // 写入整数字符串 out 用户ID 1001 | 操作登录 std::endl; // 写入浮点数 out 温度 25.5 ℃ std::endl; out.close(); return 0; }2单字符写入put()写入单个字符适合逐字符输出std::ofstream out(char.txt); out.put(H); out.put(e); out.put(l); out.put(l); out.put(o); out.put(\n); // 写入换行符 // 文件内容Hello五、二进制文件读写二进制文件以字节为单位读写不处理换行符等特殊字符直接读写原始数据适合图片、视频、可执行文件、自定义结构体等非文本数据。1. 核心要求打开时必须指定std::ios::binary模式。读写使用read()和write()方法而非/。2. 二进制读操作read()// 函数签名istream read(char* buffer, std::streamsize size); // buffer存储读取数据的缓冲区char* 类型 // size要读取的字节数示例读取整数4 字节#include iostream #include fstream int main() { // 二进制只读打开 std::ifstream in(data.bin, std::ios::in | std::ios::binary); if (!in) { std::cerr 打开失败 std::endl; return 1; } int num; // 读取4字节int的大小到num中 in.read(reinterpret_castchar*(num), sizeof(num)); std::cout 读取整数 num std::endl; in.close(); return 0; }3. 二进制写操作write()// 函数签名ostream write(const char* buffer, std::streamsize size); // buffer要写入的数据缓冲区const char* 类型 // size要写入的字节数示例写入整数 结构体#include iostream #include fstream #include string // 自定义结构体 struct Student { int id; char name[20]; float score; }; int main() { // 二进制只写打开 std::ofstream out(stu.bin, std::ios::out | std::ios::binary); if (!out) { std::cerr 打开失败 std::endl; return 1; } // 1. 写入整数 int num 12345; out.write(reinterpret_castconst char*(num), sizeof(num)); // 2. 写入结构体 Student stu {1001, 张三, 95.5f}; out.write(reinterpret_castconst char*(stu), sizeof(stu)); out.close(); return 0; }注意reinterpret_castchar*是强制类型转换将任意类型指针转为char*字节指针是二进制读写的核心技巧。六、文件指针与随机访问文件流内部维护读指针和写指针文本模式下两者通常同步二进制模式下可独立操作通过指针可实现随机访问直接跳转到文件任意位置读写。1. 核心指针操作函数函数所属类功能备注seekg(pos)istream移动读指针到绝对位置gget读seekg(off, dir)istream移动读指针到相对位置off 偏移量dir 基准位置tellg()istream获取当前读指针位置返回字节数std::streamposseekp(pos)ostream移动写指针到绝对位置pput写seekp(off, dir)ostream移动写指针到相对位置同 seekgtellp()ostream获取当前写指针位置同 tellgopen: 打开指定路径的文件可指定打开模式 //C 风格字符串版本 void open(const char* filename, std::ios_base::openmode mode /* 类默认模式 */); //ifstream 默认模式std::ios::in //ofstream 默认模式std::ios::out | std::ios::trunc //fstream 默认模式std::ios::in | std::ios::out //C string 版本C11 void open(const std::string filename, std::ios_base::openmode mode /* 类默认模式 */); close: 关闭文件释放文件资源 void close(); is_open: 检查文件是否成功打开返回 bool必须优先调用 bool is_open() const; eof: 检查是否到达文件末尾end of file返回 bool bool eof() const; fail: 检查是否发生非致命错误如格式错误返回 bool bool fail() const; bad: 检查是否发生致命错误如文件损坏返回 bool bool bad() const; clear: 清除流的错误状态如 eof () 为 true 后需调用 clear () 才能继续操作 void clear(std::ios_base::iostate state std::ios_base::goodbit); //state要设置的流状态默认清除所有错误设为goodbit seekg: 移动读指针到指定位置gget //版本 1绝对位置 std::istream seekg(std::streampos pos); //版本 2相对位置 std::istream seekg(std::streamoff off, std::ios_base::seekdir dir); //off偏移字节数 //dir基准位置ios::beg/ios::cur/ios::end seekp: 移动写指针到指定位置pput //版本 1绝对位置 std::ostream seekp(std::streampos pos); //版本 2相对位置 std::ostream seekp(std::streamoff off, std::ios_base::seekdir dir); tellg: 返回当前读指针的位置字节数 std::streampos tellg() const; tellp: 返回当前写指针的位置字节数 std::streampos tellp() const;2. 基准位置std::ios_base::seekdir常量含义std::ios::beg从文件开头偏移std::ios::cur从当前位置偏移std::ios::end从文件末尾偏移3. 随机访问示例示例 1读取文件末尾 10 字节#include iostream #include fstream #include vector int main() { std::ifstream in(test.bin, std::ios::in | std::ios::binary); if (!in) return 1; // 1. 读指针移到文件末尾 in.seekg(0, std::ios::end); // 2. 获取文件总大小末尾位置的字节数 std::streampos fileSize in.tellg(); // 3. 读指针移到「末尾-10字节」的位置 in.seekg(fileSize - 10, std::ios::beg); // 4. 读取10字节 std::vectorchar buffer(10); in.read(buffer.data(), 10); // 输出读取的内容 std::cout 文件末尾10字节; for (char ch : buffer) std::cout ch; std::cout std::endl; in.close(); return 0; }示例 2修改文件指定位置的内容#include iostream #include fstream int main() { // 读写二进制打开 std::fstream fs(data.bin, std::ios::in | std::ios::out | std::ios::binary); if (!fs) return 1; // 1. 写指针移到第5字节位置绝对位置 fs.seekp(5); // 2. 写入新数据覆盖原位置内容 int newNum 999; fs.write(reinterpret_castconst char*(newNum), sizeof(newNum)); fs.close(); return 0; }七、流状态与错误处理文件流操作可能出现各种错误如文件尾、格式错误、文件损坏C 提供流状态标志和状态检查函数用于判断和处理错误。1. 流状态标志std::ios_base::iostate标志位含义std::ios::goodbit流状态正常无错误std::ios::eofbit已到达文件末尾EOFstd::ios::failbit发生非致命错误如格式错误读取整数时读到字母std::ios::badbit发生致命错误如文件损坏、磁盘故障、流被破坏2. 状态检查函数函数功能返回值等价判断标志位good()流状态是否正常bool!eof() !fail() !bad()eof()是否到达文件末尾bool(rdstate() eofbit) ! 0fail()是否发生非致命错误bool(rdstate() (failbitbadbit)) ! 0bad()是否发生致命错误bool(rdstate() badbit) ! 03. 清除错误状态clear()当流出现错误如eofbit/failbit时后续操作会失效需调用clear()清除状态// 函数签名void clear(std::ios_base::iostate state std::ios::goodbit); // 默认清除所有错误设为goodbit示例完整错误处理流程#include iostream #include fstream #include string int main() { std::ifstream in(test.txt); if (!in) { std::cerr 打开失败 std::endl; return 1; } std::string line; while (std::getline(in, line)) { // 正常处理每行内容 std::cout line std::endl; } // 读取结束后判断错误类型 if (in.eof()) { std::cout 文件读取完成正常到达末尾 std::endl; } else if (in.fail()) { std::cerr 读取格式错误非致命 std::endl; } else if (in.bad()) { std::cerr 文件读取出错致命如磁盘故障 std::endl; } // 清除错误状态如需后续操作 in.clear(); // 重新定位到文件开头可选 in.seekg(0, std::ios::beg); in.close(); return 0; }八、高级文件操作1. 获取文件大小通过读指针移到末尾 tellg ()获取文件总字节数std::ifstream in(test.bin, std::ios::binary); if (!in) return 1; in.seekg(0, std::ios::end); // 移到末尾 std::streampos fileSize in.tellg(); // 获取大小字节 in.seekg(0, std::ios::beg); // 移回开头 std::cout 文件大小 fileSize 字节 std::endl;2. 文件重命名与删除cstdioC 标准库未直接提供文件重命名 / 删除函数需使用 C 标准库的std::rename()和std::remove()#include cstdio // 必须包含 // 重命名文件rename(旧路径, 新路径) if (std::rename(old.txt, new.txt) ! 0) { std::cerr 重命名失败 std::endl; } // 删除文件remove(文件路径) if (std::remove(delete.txt) ! 0) { std::cerr 删除失败 std::endl; }3. 临时文件临时文件用于临时存储数据程序结束后自动删除有两种方式方式 1std::tmpfile()C 标准库自动删除#include cstdio // 创建临时文件二进制读写程序结束自动删除 FILE* tmpFile std::tmpfile(); if (!tmpFile) { std::cerr 创建临时文件失败 std::endl; return 1; } // 写入临时文件 std::fputs(临时数据, tmpFile); // 读取临时文件 std::rewind(tmpFile); // 移到文件开头 char buffer[100]; std::fgets(buffer, 100, tmpFile); std::cout 临时文件内容 buffer std::endl; // 无需手动关闭程序结束自动删除方式 2fstream创建临时文件手动管理std::string tmpPath tmp_ std::to_string(rand()) .tmp; std::ofstream tmpOut(tmpPath); if (tmpOut) { tmpOut 临时数据 std::endl; tmpOut.close(); // 使用临时文件... // 手动删除 std::remove(tmpPath.c_str()); }九、注意事项与最佳实践1. 路径问题相对路径相对于程序运行目录而非代码文件目录如./dict.conf当前目录、../conf/dict.conf上级目录。绝对路径如C:/test/dict.confWindows、/home/test/dict.confLinux稳定性高但移植性差。跨平台路径分隔符优先使用/Windows 和 Linux 均支持避免\Windows 专属需转义为\\。2. 资源管理RAII优先使用构造函数打开文件流对象析构时自动关闭无需手动调用close()但显式调用更规范。避免手动管理FILE*优先使用 C 文件流更安全无内存泄漏风险。3. 权限问题写文件时程序需拥有目标目录的写入权限读文件时需拥有文件的读取权限。Windows 下需避免写入系统目录如C:\WindowsLinux 下需避免写入/root等特权目录。4. 编码问题文本文件默认编码Windows 为 ANSIGBKLinux 为 UTF-8跨平台需统一为UTF-8。读写 UTF-8 文件时无需特殊处理C 流默认支持 UTF-8但需注意中文在不同编码下的字节数差异。5. 性能优化大文件读写优先使用二进制模式缓冲区如std::vectorchar减少 IO 次数。避免频繁打开 / 关闭文件长时间操作的文件打开一次即可用完再关闭。6. 错误处理必须检查is_open()否则后续操作会导致程序崩溃。读取后检查流状态区分eof正常结束和fail/bad错误结束。清除错误状态后需重新定位文件指针如seekg(0)才能继续操作。7. C11 新特性std::string版本的open()支持直接传入std::string路径无需转const char*。移动语义文件流支持移动构造 / 赋值可高效传递流对象避免拷贝。std::filesystemC17提供更强大的文件系统操作如遍历目录、获取文件属性替代部分cstdio功能。十、总结C 文件操作的核心是流对象打开模式读写方法核心逻辑可概括为选对类ifstream读、ofstream写、fstream读写。选对模式根据需求组合in/out/app/binary等。规范流程打开→检查→读写→关闭做好错误处理。区分场景文本文件用/getline/二进制文件用read/writebinary模式。优化性能大文件用二进制 缓冲区避免频繁 IO。掌握以上知识点即可应对 C 中所有文件操作场景配置读取、日志写入、数据存储、二进制处理等。常用场景示例1. 逐行读取文本文件#include fstream #include iostream #include string using namespace std; int main() { ifstream in(config.txt); if (!in) { cerr 打开失败; return 1; } string line; while (getline(in, line)) { cout 读取行 line endl; } in.close(); return 0; }2. 二进制读写结构体#include fstream #include iostream using namespace std; struct Student { int id; char name[20]; float score; }; int main() { // 写入 ofstream out(stu.bin, ios::out | ios::binary); Student s {1001, 张三, 95.5}; out.write((char*)s, sizeof(s)); out.close(); // 读取 ifstream in(stu.bin, ios::in | ios::binary); Student s_read; in.read((char*)s_read, sizeof(s_read)); cout ID s_read.id 姓名 s_read.name 分数 s_read.score endl; in.close(); return 0; }