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

