C++ 文件操作_基于传统文件操作_非filesystem

基础文件操作

文件打开模式

  • ios::in:读取模式
  • ios::out:写入模式(覆盖)
  • ios::app:追加模式
  • ios::binary:二进制模式
  • ios::ate:打开后定位到文件尾
#include <fstream>
using namespace std;

// 创建并写入文件
ofstream outFile("example.txt", ios::out);
if(outFile.is_open()){
    outFile << "Line 1\nLine 2";
    outFile.close();
}

读写文本文件

逐行读取

ifstream inFile("example.txt");
string line;
while(getline(inFile, line)){
    cout << line << endl;
}
inFile.close();

格式化写入

ofstream logFile("log.txt", ios::app);
logFile << fixed << setprecision(2);
logFile << "Transaction: " << 19.99 << endl;

二进制文件操作

结构体读写

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

// 写入二进制
Person p = {"Alice", 30};
ofstream binOut("data.bin", ios::binary);
binOut.write((char*)&p, sizeof(Person));

// 读取二进制
ifstream binIn("data.bin", ios::binary);
Person p2;
binIn.read((char*)&p2, sizeof(Person));

文件定位

随机访问

fstream file("data.dat", ios::in | ios::out | ios::binary);
file.seekg(10, ios::beg);  // 移动读取指针
file.seekp(0, ios::end);   // 移动写入指针
streampos pos = file.tellg(); // 获取当前位置

错误处理

状态检查

ifstream file("missing.txt");
if(!file){
    cerr << "Error: " << strerror(errno) << endl;
}

// 清除状态标志
file.clear();
file.ignore(numeric_limits<streamsize>::max(), '\n');

高级应用

内存映射文件(Windows API)

HANDLE hFile = CreateFile("large.bin", GENERIC_READ, 
    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
LPVOID pData = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
// 使用指针访问数据...
UnmapViewOfFile(pData);
CloseHandle(hMap);
CloseHandle(hFile);

性能优化

缓冲区设置

char buffer[1024];
ifstream fastFile("bigfile.txt");
fastFile.rdbuf()->pubsetbuf(buffer, 1024);

跨平台注意事项

  • Linux/Windows换行符差异(\n vs \r\n
  • 路径分隔符(/ vs \
  • 文件权限管理(chmod vs ACL)

扩展方向

  1. 加密文件操作:结合OpenSSL实现AES加密
  2. 多线程读写:使用std::mutex保护文件操作
  3. 网络文件传输:通过SFTP协议实现远程访问
  4. 日志系统设计:异步写入与滚动文件管理
1. 加密文件操作:结合OpenSSL实现AES加密

文件加密是保护敏感数据的关键。我们使用OpenSSL的AES算法(如AES-256-CBC)对文件内容进行加密和解密。核心原理是:读取文件时解密数据,写入时加密数据。OpenSSL提供EVP接口,简化了加密流程。
实现步骤

  • 初始化OpenSSL加密上下文。
  • 使用fstream读取文件,将数据传入EVP加密函数。
  • 将加密后数据写入新文件(或覆盖原文件)。
  • 解密过程类似,但使用EVP解密函数。

代码示例

#include <fstream>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <vector>

// 加密函数:输入源文件路径、输出文件路径和密钥
void encrypt_file(const std::string& input_path, const std::string& output_path, const std::vector<unsigned char>& key) {
    std::ifstream in_file(input_path, std::ios::binary);
    std::ofstream out_file(output_path, std::ios::binary);
    if (!in_file || !out_file) {
        throw std::runtime_error("文件打开失败");
    }

    // 初始化OpenSSL上下文
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) {
        throw std::runtime_error("EVP上下文初始化失败");
    }
    // 设置AES-256-CBC加密模式
    if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key.data(), nullptr) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        throw std::runtime_error("加密初始化失败");
    }

    // 缓冲区处理
    std::vector<unsigned char> in_buf(1024), out_buf(1024 + EVP_MAX_BLOCK_LENGTH);
    int out_len;
    while (in_file.read(reinterpret_cast<char*>(in_buf.data()), in_buf.size())) {
        int in_len = in_file.gcount();
        if (EVP_EncryptUpdate(ctx, out_buf.data(), &out_len, in_buf.data(), in_len) != 1) {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("加密更新失败");
        }
        out_file.write(reinterpret_cast<char*>(out_buf.data()), out_len);
    }

    // 处理最后块
    if (EVP_EncryptFinal_ex(ctx, out_buf.data(), &out_len) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        throw std::runtime_error("加密结束失败");
    }
    out_file.write(reinterpret_cast<char*>(out_buf.data()), out_len);

    // 清理资源
    EVP_CIPHER_CTX_free(ctx);
}

// 解密函数类似,使用EVP_DecryptInit_ex等
int main() {
    std::vector<unsigned char> key(32, 0xAA); // 32字节密钥(AES-256)
    encrypt_file("plain.txt", "encrypted.bin", key);
    // decrypt_file("encrypted.bin", "decrypted.txt", key); // 解密示例
    return 0;
}

注意事项

  • 密钥管理:实际应用中应使用安全密钥存储(如密钥派生函数)。
  • 错误处理:OpenSSL错误可通过ERR_print_errors_fp(stderr)输出。
  • 编译命令:g++ -o encrypt encrypt.cpp -lssl -lcrypto

2. 多线程读写:使用std::mutex保护文件操作

在多线程环境中,文件操作需避免竞争条件。std::mutex提供互斥锁,确保同一时间只有一个线程访问文件。核心原理是:在文件读写前加锁,操作后解锁。
实现步骤

  • 定义一个文件操作类,封装fstreamstd::mutex
  • 在读写方法中,使用std::lock_guard自动管理锁生命周期。
  • 支持并发读取(允许多线程读)和独占写入(只允许一个线程写)。

代码示例

#include <fstream>
#include <mutex>
#include <thread>
#include <vector>

class ThreadSafeFile {
public:
    ThreadSafeFile(const std::string& path) : file_path(path) {}

    // 线程安全写入
    void write(const std::string& data) {
        std::lock_guard<std::mutex> lock(write_mutex); // 写操作互斥
        std::ofstream out_file(file_path, std::ios::app); // 追加模式
        if (!out_file) {
            throw std::runtime_error("文件打开失败");
        }
        out_file << data << std::endl;
    }

    // 线程安全读取(允许多线程并发读)
    std::string read() {
        std::lock_guard<std::mutex> lock(read_mutex); // 读操作互斥(避免写冲突)
        std::ifstream in_file(file_path);
        if (!in_file) {
            throw std::runtime_error("文件打开失败");
        }
        std::string content((std::istreambuf_iterator<char>(in_file)), std::istreambuf_iterator<char>());
        return content;
    }

private:
    std::string file_path;
    std::mutex write_mutex; // 写锁
    std::mutex read_mutex;  // 读锁(可优化为读写锁,但C++17需用std::shared_mutex)
};

void worker(ThreadSafeFile& file, int id) {
    file.write("Thread " + std::to_string(id) + " writes data");
}

int main() {
    ThreadSafeFile safe_file("thread_log.txt");
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back(worker, std::ref(safe_file), i);
    }
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "File content: " << safe_file.read() << std::endl;
    return 0;
}

注意事项

  • 性能优化:对于读多写少场景,可使用std::shared_mutex(C++17)提升并发度。
  • 锁粒度:尽量缩小锁范围以减少阻塞。
  • 编译命令:g++ -o thread_safe thread_safe.cpp -lpthread

3. 网络文件传输:通过SFTP协议实现远程访问

SFTP(SSH File Transfer Protocol)提供安全的远程文件传输。我们使用libssh库实现SFTP客户端,结合fstream处理本地文件。核心原理是:建立SSH连接后,通过SFTP会话上传或下载文件。
实现步骤

  • 初始化libssh会话,认证(如密码或密钥)。
  • 创建SFTP会话,打开远程文件句柄。
  • fstream读写本地文件,通过SFTP函数传输数据块。

代码示例

#include <fstream>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include <iostream>

void sftp_upload(const std::string& local_path, const std::string& remote_path, 
                 const std::string& host, const std::string& user, const std::string& password) {
    // 初始化SSH会话
    ssh_session session = ssh_new();
    if (!session) {
        throw std::runtime_error("SSH会话创建失败");
    }
    ssh_options_set(session, SSH_OPTIONS_HOST, host.c_str());
    ssh_options_set(session, SSH_OPTIONS_USER, user.c_str());
    if (ssh_connect(session) != SSH_OK) {
        ssh_free(session);
        throw std::runtime_error("SSH连接失败");
    }
    if (ssh_userauth_password(session, nullptr, password.c_str()) != SSH_AUTH_SUCCESS) {
        ssh_disconnect(session);
        ssh_free(session);
        throw std::runtime_error("认证失败");
    }

    // 初始化SFTP会话
    sftp_session sftp = sftp_new(session);
    if (!sftp) {
        ssh_disconnect(session);
        ssh_free(session);
        throw std::runtime_error("SFTP会话创建失败");
    }
    if (sftp_init(sftp) != SSH_OK) {
        sftp_free(sftp);
        ssh_disconnect(session);
        ssh_free(session);
        throw std::runtime_error("SFTP初始化失败");
    }

    // 打开本地文件
    std::ifstream local_file(local_path, std::ios::binary);
    if (!local_file) {
        sftp_free(sftp);
        ssh_disconnect(session);
        ssh_free(session);
        throw std::runtime_error("本地文件打开失败");
    }

    // 创建远程文件
    sftp_file remote_file = sftp_open(sftp, remote_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
    if (!remote_file) {
        local_file.close();
        sftp_free(sftp);
        ssh_disconnect(session);
        ssh_free(session);
        throw std::runtime_error("远程文件打开失败");
    }

    // 传输数据
    char buffer[1024];
    while (local_file.read(buffer, sizeof(buffer))) {
        int bytes_read = local_file.gcount();
        if (sftp_write(remote_file, buffer, bytes_read) != bytes_read) {
            sftp_close(remote_file);
            local_file.close();
            sftp_free(sftp);
            ssh_disconnect(session);
            ssh_free(session);
            throw std::runtime_error("SFTP写入失败");
        }
    }

    // 清理资源
    sftp_close(remote_file);
    local_file.close();
    sftp_free(sftp);
    ssh_disconnect(session);
    ssh_free(session);
}

int main() {
    sftp_upload("local.txt", "/remote/path/file.txt", "example.com", "user", "password");
    // 下载类似,使用sftp_read和ofstream
    return 0;
}

注意事项

  • 安全性:避免硬编码密码,使用密钥认证更安全。
  • 错误处理:libssh错误可通过ssh_get_error(session)获取。
  • 编译命令:g++ -o sftp_upload sftp_upload.cpp -lssh

4. 日志系统设计:异步写入与滚动文件管理

日志系统需高性能和可靠性。我们设计一个异步日志器:主线程收集日志消息,后台线程负责写入文件;同时支持滚动文件管理(如按大小分割文件)。核心原理是:使用生产者-消费者模型,通过队列缓冲日志消息。
实现步骤

  • 定义日志队列(使用std::queuestd::mutex)。
  • 启动后台线程,循环检查队列并写入文件。
  • 滚动管理:当文件大小超过阈值时,关闭当前文件,创建新文件(如按时间戳命名)。

代码示例

#include <fstream>
#include <mutex>
#include <queue>
#include <thread>
#include <chrono>
#include <string>
#include <atomic>

class AsyncLogger {
public:
    AsyncLogger(const std::string& base_path, size_t max_size = 1024 * 1024) 
        : base_path(base_path), max_file_size(max_size), running(true), current_size(0) {
        worker_thread = std::thread(&AsyncLogger::process_queue, this);
        open_new_file(); // 初始文件
    }

    ~AsyncLogger() {
        running = false;
        worker_thread.join(); // 等待线程结束
        if (out_file.is_open()) out_file.close();
    }

    void log(const std::string& message) {
        std::lock_guard<std::mutex> lock(queue_mutex);
        log_queue.push(message);
    }

private:
    std::string base_path;
    size_t max_file_size;
    std::ofstream out_file;
    std::atomic<size_t> current_size;
    std::queue<std::string> log_queue;
    std::mutex queue_mutex, file_mutex;
    std::thread worker_thread;
    std::atomic<bool> running;

    void open_new_file() {
        std::lock_guard<std::mutex> file_lock(file_mutex);
        if (out_file.is_open()) out_file.close();
        auto now = std::chrono::system_clock::now();
        auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
        std::string new_path = base_path + "_" + std::to_string(timestamp) + ".log";
        out_file.open(new_path, std::ios::app);
        if (!out_file) throw std::runtime_error("日志文件打开失败");
        current_size = 0;
    }

    void process_queue() {
        while (running || !log_queue.empty()) {
            std::queue<std::string> local_queue;
            {
                std::lock_guard<std::mutex> lock(queue_mutex);
                if (!log_queue.empty()) {
                    local_queue.swap(log_queue); // 批量处理减少锁竞争
                }
            }

            while (!local_queue.empty()) {
                std::string msg = local_queue.front();
                local_queue.pop();
                write_to_file(msg);
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 减少CPU占用
        }
    }

    void write_to_file(const std::string& msg) {
        std::lock_guard<std::mutex> file_lock(file_mutex);
        if (!out_file) return;
        out_file << msg << std::endl;
        current_size += msg.size() + 1; // 估算大小
        if (current_size >= max_file_size) {
            open_new_file(); // 滚动新文件
        }
    }
};

int main() {
    AsyncLogger logger("app_log");
    logger.log("系统启动");
    // 多线程调用logger.log安全
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return 0;
}

注意事项

  • 异步性能:队列大小可限制,防止内存溢出。
  • 滚动策略:可扩展为按时间滚动(如每天新文件)。
  • 编译命令:g++ -o logger logger.cpp -lpthread

总结

C++fstrem文件操作非常重要,要使文件信息保存恰当,安全性高,性能强等等,希望这篇文章能帮助到你。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值