C++ —— 文件操作(流式操作)

发布于:2025-04-08 ⋅ 阅读:(37) ⋅ 点赞:(0)

我们之前已经了解过了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);
    

模式组合

可以组合多个模式使用,使用按位或运算符 |

常见组合

  1. 普通文本读取

    std::ifstream textFile("text.txt", std::ios::in);
    
  2. 二进制读取

    std::ifstream binFile("data.bin", std::ios::in | std::ios::binary);
    
  3. 从文件末尾开始读取

    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); // 回到文件开头开始读取
        // ...读取操作...
    }
    

重要注意事项

  1. 文件不存在

    • 如果文件不存在且只使用 std::ios::in,打开会失败
    • 检查是否成功打开:
      if (!file.is_open()) {
          // 处理错误
      }
      
  2. 模式兼容性

    • ifstream 不支持写入模式(如 std::ios::out
    • 如果需要写入,应使用 fstream
  3. 二进制模式

    • 在Windows平台上,文本模式会自动转换 \r\n\n
    • 二进制模式保持原始字节不变
  4. 默认行为

    • 如果不指定任何模式,默认是 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;
}

注意事项

  1. 模式组合fstream 没有默认模式,必须显式指定 inout
  2. 文件存在性:使用 in 模式时文件必须存在
  3. 二进制模式:处理非文本文件时应使用 binary 模式
  4. 指针同步:读写切换时需要调用 seekg()seekp()
  5. 内存管理:使用 write() 写入二进制数据时要注意数据对齐

fstream 提供了灵活的文件操作能力,适合需要同时读写文件的场景。对于简单的只读或只写操作,可以考虑使用 ifstreamofstream

文件流的成员函数

在 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;
}

注意事项

  1. 模式标志
    • ios::in(读)、ios::out(写)、ios::binary(二进制)、ios::app(追加)等可组合使用。
  2. 错误处理
    始终检查 is_open()good() 避免未定义行为。
  3. 资源释放
    显式调用 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>,除非有明确的性能或控制需求。


网站公告

今日签到

点亮在社区的每一天
去签到