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

C++文本压缩程序保存后数据损坏问题求助

问题分析与修复方案

核心问题拆解

你的文本压缩程序出现乱码和数据损坏,主要源于以下几个关键错误:

  • 文本模式读写二进制数据:默认fstream打开方式为文本模式,会自动转换换行符(如Windows下\n转\r\n),且部分控制字符(如ASCII 0x1A)会被误判为EOF,导致二进制数据损坏。
  • 字符读取丢失空白内容:使用file >> ch会跳过所有空白字符(空格、换行、制表符等),导致原文件内容不完整,压缩源数据错误。
  • 补位逻辑无溯源信息:直接追加'1'补位,但未记录补位位数,解压时无法区分原始数据与补位内容。
  • 元数据与压缩数据存储混乱:将文本形式的二进制字符串(如00000101)与二进制压缩数据混存,且存储顺序错误,导致后续无法正确拆分解码信息。

修复后的完整代码

#include <iostream>
#include <string>
#include <bitset>
#include <map>
#include <vector>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <sstream>
using namespace std;

int main()
{
    vector<char> lista;
    map<char,string> znaki;
    string szyfr;
    char ch;

    // 二进制模式打开输入文件,避免文本模式字符转换
    fstream file("test.txt", ios::in | ios::binary);
    if (!file.is_open()) {
        cerr << "无法打开输入文件" << endl;
        return 1;
    }

    // 读取所有字符(含空白字符)
    while (file.get(ch)) {
        if (find(lista.begin(), lista.end(), ch) == lista.end()) {
            lista.push_back(ch);
        }
    }
    sort(lista.begin(), lista.end());
    int lista_rozm = lista.size();

    string dekod_info;
    // 直接以字节存储字符数量(替代文本二进制字符串)
    dekod_info += static_cast<char>(lista_rozm);
    int length = ceil(log2(lista.size()));
    // 处理空列表边界情况
    if (length == 0) length = 1;

    for (int i = 0; i < lista.size(); i++) {
        dekod_info += lista[i];
        string binaryString = bitset<8>(i).to_string();
        if (binaryString.size() > length)
            binaryString = binaryString.substr(binaryString.size() - length);
        else if (binaryString.size() < length)
            binaryString = string(length - binaryString.size(), '0') + binaryString;
        znaki.insert(pair<char,string>(lista[i], binaryString));
    }
    file.close();

    // 重新二进制模式打开读取原文件
    file.open("test.txt", ios::in | ios::binary);
    if (!file.is_open()) {
        cerr << "无法重新打开输入文件" << endl;
        return 1;
    }
    char ch2;
    while (file.get(ch2)) {
        szyfr += znaki[ch2];
    }
    file.close();

    // 记录补位位数,用0补位(避免与原始数据混淆)
    int pad_bits = 8 - (szyfr.size() % 8);
    if (pad_bits != 8) {
        szyfr += string(pad_bits, '0');
    } else {
        pad_bits = 0;
    }

    // 二进制字符串转字节序列
    string output;
    for (size_t i = 0; i < szyfr.size(); i += 8) {
        bitset<8> bits(szyfr.substr(i, 8));
        output += static_cast<char>(bits.to_ulong());
    }

    // 二进制模式写入输出文件,按顺序存储元数据+压缩数据
    fstream file2("wynik.txt", ios::out | ios::binary);
    if (!file2.is_open()) {
        cerr << "无法打开输出文件" << endl;
        return 1;
    }
    file2.put(static_cast<char>(pad_bits)); // 先存补位位数
    file2.write(dekod_info.c_str(), dekod_info.size()); // 存字符数量+字符列表
    file2.write(output.c_str(), output.size()); // 存压缩数据
    file2.close();

    return 0;
}

关键修复说明

  1. 二进制模式读写:所有文件操作添加ios::binary标志,彻底避免文本模式下的字符转换,保证二进制数据完整性。
  2. 完整读取字符:用file.get(ch)替代file >> ch,读取文件中每一个字符(包括空白字符),确保压缩源数据与原文件完全一致。
  3. 补位信息可溯源:记录补位位数并存储到输出文件开头,解压时可精准去除补位内容,避免数据解析错误。
  4. 元数据存储优化:将字符数量以二进制字节形式存储(而非文本二进制字符串),减少冗余开销;调整存储顺序为「补位位数→字符元数据→压缩数据」,方便后续解码程序拆分解析。
  5. 可靠的二进制转字节:直接按8位拆分二进制字符串转换为字节,避免stringstream可能出现的意外问题。

内容的提问来源于stack exchange,提问作者Kuba Herka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:04:56