You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ XOR加密程序遇ASCII控制字符致std::ifstream读取中断的解决方法

解决XOR加密后文件读取提前终止的问题

你遇到的问题很典型:默认的文本模式流会把ASCII 26(Ctrl+Z,也就是你说的#26)当作文件结束符,导致读取加密文件时提前停止。加密后的内容本质是二进制数据(包含任意字节值),不能用文本模式处理,必须切换到二进制模式来读写文件。

问题根源

当你用std::ifstream默认打开文件时,它处于文本模式:

  • 在Windows系统中,文本模式会将ASCII 26(0x1A)识别为EOF,一旦遇到这个字符,流就会停止读取。
  • 文本模式还会自动转换换行符(比如把\n转成\r\n),这会破坏加密后的二进制数据,导致解密出错。

而XOR加密会生成包含任意字节的内容,很容易出现像ASCII 26这样的控制字符,所以必须用二进制模式来处理这些文件。

解决方案

你需要对代码做以下几个关键修改:

1. 用二进制模式打开所有文件

在创建std::ifstream和std::ofstream时,添加std::ios::binary标志,告诉流以二进制模式处理数据,不做任何字符转换。

2. 替换getline为二进制读取方式

std::getline是为文本设计的,它依赖换行符分割内容,而加密后的二进制数据可能包含任意字节(包括换行符或没有换行符),所以应该直接读取整个文件的字节内容,而不是按行读取。

修改后的代码示例

下面是调整后的Encrypt和Decrypt函数,以及对应的修改说明:

加密函数修改

void Encrypt(char encryptionKey, std::string filename) {
    // 以二进制模式打开源文件
    std::ifstream sourceFile(filename, std::ios::binary);
    // 以二进制模式创建输出文件
    std::ofstream outputFile(
        filename.substr(0, filename.find_last_of("\\")) + "\\Encrypted" + filename.substr(filename.find_last_of("\\") + 1),
        std::ofstream::out | std::ofstream::trunc | std::ios::binary
    );

    if (sourceFile.is_open() && outputFile.is_open()) {
        std::cout << "Opening file: " + filename + " for encryption" << std::endl;
        
        // 一次性读取整个文件的内容到字符串中
        std::string sourceContent(
            (std::istreambuf_iterator<char>(sourceFile)),
            std::istreambuf_iterator<char>()
        );

        std::string outputContent;
        outputContent.reserve(sourceContent.size()); // 预分配内存,提升效率

        for (char c : sourceContent) {
            char encryptedByte = c ^ encryptionKey;
            outputContent.push_back(encryptedByte);
        }

        // 写入加密后的内容
        outputFile.write(outputContent.data(), outputContent.size());
        std::cout << "Encrypted " << sourceContent.size() << " bytes successfully." << std::endl;
    } else {
        std::cerr << "Failed to open file(s) for encryption." << std::endl;
    }

    sourceFile.close();
    outputFile.close();
}

解密函数修改

void Decrypt(unsigned int encryptionKey, std::string filename) {
    // 同样以二进制模式打开加密文件
    std::ifstream sourceFile(filename, std::ios::binary);
    std::ofstream outputFile(
        filename.substr(0, filename.find_last_of("\\")) + "\\Decrypted" + filename.substr(filename.find_last_of("\\") + 1),
        std::ofstream::out | std::ofstream::trunc | std::ios::binary
    );

    if (sourceFile.is_open() && outputFile.is_open()) {
        std::cout << "Opening file: " + filename + " for decryption" << std::endl;
        
        // 一次性读取所有加密字节
        std::string encryptedContent(
            (std::istreambuf_iterator<char>(sourceFile)),
            std::istreambuf_iterator<char>()
        );

        std::string decryptedContent;
        decryptedContent.reserve(encryptedContent.size());

        for (char c : encryptedContent) {
            char decryptedByte = c ^ encryptionKey;
            decryptedContent.push_back(decryptedByte);
        }

        // 写入解密后的内容
        outputFile.write(decryptedContent.data(), decryptedContent.size());
        std::cout << "Decrypted " << encryptedContent.size() << " bytes successfully." << std::endl;
    } else {
        std::cerr << "Failed to open file(s) for decryption." << std::endl;
    }

    sourceFile.close();
    outputFile.close();
}

额外优化点

  • 原来的while (sourceFile.good())判断方式容易出错,因为good()的状态是在读取操作之后才更新的,可能导致最后一次读取无效数据。用std::istreambuf_iterator一次性读取整个文件更可靠。
  • 预分配字符串内存(reserve)可以避免频繁的内存分配,提升程序效率。
  • 添加了错误检查(判断文件是否成功打开),让程序更健壮。

这样修改后,你的程序就能完整读取加密后的文件,不会因为遇到ASCII控制字符而提前终止了。

内容的提问来源于stack exchange,提问作者Tim Roberts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:11:54