使用CryptoPP解密时,读写同一文件为何执行后得到空文件?
问题原因与解决方案
核心问题
当输入输出指向同一文件时,std::ofstream的默认打开模式会立即截断文件(隐含std::ios::trunc标志),这会让后续的std::ifstream读不到任何原始数据,最终解密输出为空文件。
修复方案
方案1:内存中转(适合小文件)
先把原文件内容全部读入内存,再打开文件写入解密后的数据:
void decrypt(const aes_key_t& key, const aes_iv_t& iv, const std::string& filename) { CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption cipher{}; cipher.SetKeyWithIV(key.data(), key.size(), iv.data()); // 读取文件到内存缓冲区 std::ifstream in{ filename, std::ios::binary | std::ios::ate }; std::streamsize file_size = in.tellg(); in.seekg(0, std::ios::beg); std::vector<char> file_buffer(file_size); if (!in.read(file_buffer.data(), file_size)) { // 处理读取失败逻辑,比如抛出异常或返回错误码 return; } // 打开文件并写入解密后的数据 std::ofstream out{ filename, std::ios::binary }; CryptoPP::StringSource{ file_buffer.data(), file_size, true, new CryptoPP::StreamTransformationFilter{ cipher, new CryptoPP::FileSink{out}} }; }
方案2:临时文件中转(适合大文件)
用临时文件存储解密结果,完成后替换原文件:
#include <cstdio> void decrypt(const aes_key_t& key, const aes_iv_t& iv, const std::string& filename) { CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption cipher{}; cipher.SetKeyWithIV(key.data(), key.size(), iv.data()); const std::string temp_file = filename + ".decrypt.tmp"; // 解密到临时文件 std::ifstream in{ filename, std::ios::binary }; std::ofstream out{ temp_file, std::ios::binary }; CryptoPP::FileSource{ in, true, new CryptoPP::StreamTransformationFilter{ cipher, new CryptoPP::FileSink{out}} }; // 关闭流确保数据落盘 in.close(); out.close(); // 替换原文件 std::remove(filename.c_str()); std::rename(temp_file.c_str(), filename.c_str()); }
注意事项
- 操作敏感文件前,务必做好备份,防止解密失败导致数据丢失;
- 内存中转方案会占用与文件大小相同的内存,大文件建议用临时文件方案;
- 临时文件方案需要处理异常情况(比如解密失败时删除临时文件),避免残留垃圾文件。
内容的提问来源于stack exchange,提问作者jamie_0101
相关产品推荐
相关产品推荐

