【C++与Linux基础】文件篇 -语言特性上的文件操作

【C++与Linux基础】文件篇 – 语言特性上的文件操作

在 C++ 中进行文件操作,主要依赖两种方式:

  1. C++ 标准库<fstream>)—— 现代 C++ 推荐方式,跨平台,面向对象风格
  2. C 风格文件操作<cstdio> 中的 fopenfread 等)—— 仍然大量存在,尤其在与 C 代码混合、性能敏感或 Linux 系统编程场景中

此外,在 Linux 环境下,C++ 程序也经常直接使用系统调用<unistd.h>openreadwrite 等)来实现更底层的文件/IO 操作。

下面按使用频率和推荐度逐一对比说明。

1. C++ 标准库方式(推荐现代写法)

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    // ------------------------------
    // 1. 写文件(推荐方式)
    // ------------------------------
    std::ofstream ofs("output.txt", std::ios::out | std::ios::trunc);
    if (!ofs.is_open()) {
        std::cerr << "无法打开文件\n";
        return 1;
    }

    ofs << "Hello, C++ file!\n";
    ofs << "当前行: " << __LINE__ << "\n";
    ofs << 3.14159 << " " << 42 << "\n";

    // 也可以用格式化(C++20 之后更方便)
    // ofs << std::format("pi = {:.4f}\n", 3.1415926535);

    ofs.close();  // 通常可以省略,析构时自动关闭


    // ------------------------------
    // 2. 读文件 - 按行读取(最常用)
    // ------------------------------
    std::ifstream ifs("output.txt");
    if (!ifs.is_open()) {
        std::cerr << "无法打开文件\n";
        return 1;
    }

    std::string line;
    while (std::getline(ifs, line)) {
        std::cout << line << '\n';
    }


    // ------------------------------
    // 3. 一次性读入全部内容(适合小文件)
    // ------------------------------
    std::ifstream in("config.ini", std::ios::in | std::ios::binary);
    if (in) {
        std::string content((std::istreambuf_iterator<char>(in)),
                            std::istreambuf_iterator<char>());
        std::cout << "文件全部内容长度: " << content.size() << '\n';
    }


    // ------------------------------
    // 4. 读写二进制文件
    // ------------------------------
    struct Record {
        int id;
        double value;
        char name[32];
    };

    // 写
    std::ofstream bin_out("data.bin", std::ios::binary);
    Record r{1001, 3.14159, "SensorA"};
    bin_out.write(reinterpret_cast<const char*>(&r), sizeof(r));

    // 读
    std::ifstream bin_in("data.bin", std::ios::binary);
    Record r2;
    if (bin_in.read(reinterpret_cast<char*>(&r2), sizeof(r2))) {
        std::cout << r2.id << " " << r2.value << " " << r2.name << '\n';
    }

    return 0;
}

C++ 文件流常用状态与标志

打开模式说明常用组合
std::ios::in以读方式打开读文件
std::ios::out以写方式打开(默认清空)写文件
std::ios::app追加模式日志文件
std::ios::trunc如果文件存在则清空(out 默认)重写文件
std::ios::binary二进制模式(不转换换行符)读写图片、struct、protobuf 等
std::ios::ate打开后立即定位到文件末尾追加写

2. C 风格文件操作(仍然非常常见)

#include <cstdio>
#include <cstring>

int main()
{
    // 写文件
    FILE* fp = fopen("log.txt", "w");
    if (!fp) {
        perror("fopen");
        return 1;
    }

    fprintf(fp, "Time: %ld  Error: %s\n", time(nullptr), "disk full");
    fputs("critical alert\n", fp);

    fclose(fp);


    // 读文件(按块读)
    char buf[4096];
    FILE* in = fopen("large.bin", "rb");
    if (in) {
        size_t n;
        while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
            // 处理 buf[0..n-1]
        }
        fclose(in);
    }

    // 定位 + 追加写
    FILE* log = fopen("server.log", "a+");
    fseek(log, 0, SEEK_END);   // 可省略,因为 a 模式默认追加
    fprintf(log, "[INFO] connection from %s\n", "192.168.1.100");

    return 0;
}

3. Linux 系统调用方式(底层、最灵活)

#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cstring>
#include <iostream>

int main()
{
    // 打开文件
    int fd = open("raw.dat", O_RDWR | O_CREAT, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 写
    const char* msg = "Hello from syscall\n";
    write(fd, msg, strlen(msg));

    // 定位
    off_t pos = lseek(fd, 0, SEEK_SET);
    if (pos == -1) perror("lseek");

    // 读
    char buf[128];
    ssize_t n = read(fd, buf, sizeof(buf)-1);
    if (n > 0) {
        buf[n] = '\0';
        std::cout << "Read: " << buf;
    }

    close(fd);

    // 追加写示例
    int logfd = open("/var/log/app.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
    if (logfd != -1) {
        const char* line = "ERROR: connection timeout\n";
        write(logfd, line, strlen(line));
        close(logfd);
    }

    return 0;
}

4. 三种方式对比总结(2025–2026 视角)

方式跨平台易用性性能推荐场景现代 C++ 推荐度
std::fstream★★★★★中等日常开发、配置、日志、中等大小文件★★★★★
C 风格 FILE*★★★★与 C 库交互、性能敏感、嵌入式、老代码★★★
Linux 系统调用★★最高高性能服务器、驱动开发、大文件处理、零拷贝★★(特定场景)

5. 现代 C++ 写文件操作的推荐实践(2024+)

  1. 优先使用 std::ofstream / std::ifstream
  2. 小文件直接读入 std::string(如上文方式)
  3. 大文件建议分块读取(避免一次性读入全部内容)
  4. 总是检查打开是否成功
  5. RAII 原则:尽量依赖析构自动关闭(不显式 close()
  6. 日志类场景 → 考虑 std::ofstream + std::ios::app
  7. 二进制数据 → 务必加上 std::ios::binary
  8. 异常安全 → 可开启 ifs.exceptions(std::ios::failbit | std::ios::badbit);

6. 常见问题快速定位

  • 文件打不开 → 检查路径、权限、是否被其他进程占用
  • Windows 和 Linux 换行符不同 → 文本模式下自动处理,二进制模式需注意
  • 写不进去 → 忘记 flush()close(),或磁盘满
  • 读到乱码 → 忘记 std::ios::binary 或编码问题

下一节可以深入讲:

  • RAII 封装的文件类
  • mmap 内存映射文件
  • 异步文件 IO(io_uring)
  • 大文件分块读写 + 进度显示

你更想往哪个方向继续?或者有具体场景(日志、配置、二进制、超大文件等)想看最优实现?

文章已创建 4424

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部