不能直接用std::ifstream读整块再异或,因为大文件会触发OOM或卡顿;必须分块读取、逐块异或、逐块写入,全程固定内存占用,且务必使用binary模式并用gcount()精确获取实际读取字节数。

为什么不能直接用 std::ifstream 读整块再异或?
因为文件可能超内存(比如几百 MB 的日志或资源文件),一次性 read() 到缓冲区会触发 OOM 或卡顿。流式处理的核心是分块读取、逐块异或、逐块写入,全程只占用固定内存(如 4KB–64KB)。关键不是“能不能做”,而是“怎么控制边界不损坏数据”——尤其是二进制文件没有行概念,不能依赖 getline(),必须用 read() + gcount() 精确获取实际读取字节数。
std::ifstream 和 std::ofstream 必须用 std::ios::binary 模式
漏掉这个标志会导致 Windows 下换行符 \r\n 被自动转成 \n,异或后还原时字节错位,文件彻底损坏。所有涉及非文本二进制操作的场景,都必须显式指定:
std::ifstream fin("input.bin", std::ios::binary);
std::ofstream fout("output.bin", std::ios::binary);
常见错误:只给输入加 binary,输出用默认文本模式——这会让 fout.write() 在 Windows 上把 0x0A 自动补 0x0D,异或密钥哪怕只是 0xFF,还原时也对不上。
如何安全处理最后一块不足缓冲区大小的数据?
用 read() 后必须检查 gcount(),不能假设每次读满缓冲区。例如设缓冲区为 8192 字节,但文件末尾只剩 3 字节,此时 gcount() 返回 3,若直接用 8192 做异或循环,就会把栈上未初始化的垃圾内存也参与运算。
立即学习“C++免费学习笔记(深入)”;
- 正确做法:以
gcount()为实际长度做异或 - 错误写法:
for (int i = 0; i - 正确写法:
for (int i = 0; i (fin.gcount()); ++i) buf[i] ^= key; - 密钥可单字节(如
0x55),也可循环使用多字节密钥(需维护密钥索引)
异或混淆不是加密,别在生产环境当加密用
异或本身可逆且无扩散性:相同密钥下,0x00 异或后还是 0x00,明文中的重复字节模式在密文中完全保留。它只能防 casual inspection(比如防止配置文件被直接文本查看),无法抵抗任何有基本分析能力的对手。如果真需要保密,用 libsodium 或 OpenSSL 做 AES-GCM;如果只是想快速让文件“看不出原始内容”,异或够用,但务必记住:密钥硬编码在代码里等于没混淆。


















