在写哈夫曼编码压缩与解压文件的问题时,Java是非常容器且没有问题的;但是在C语言里面,这个文件读写就变得很困难;当我尝试写入一个结构体时,发现没有问题,但是实际并没有将map的内容顺利写入;而且我发现不管是fread还是fwrite,都无法将无法提前确定大小的map集合写入;太痛苦了;感觉我已经在尝试学习Java序列化的解决思路了。
代码如下:(原本以为已经写完的我,才发现只是开了个头;C语言的文件读写好折磨,太折磨了)
文章地址:
# include
# include
# include
# include
# include
# include
# include
# include
using namespace std;
// 读取文件得到int数组转化成哈夫曼编码得到哈夫曼树,进行压缩与解压
typedef int elementType;
struct Node
{
elementType data;
int value;
Node* left;
Node* right;
};
struct ZipStruct
{
map encodeMap; // 由哈夫曼树生成的编码表
int size = 0; // 所占字节数
int zipSize = 0; // 所占比特数(用于处理末尾数字补全)
};
struct Zip
{
string originFileName;
string destFileName; // 压缩生成的文件名
elementType* buff = NULL; // 读入的文件字符数据
mapint> twoTuple; // 字符串转化为二元组形式,表示各个字符出现的频率
map encodeMap; // 由哈夫曼树生成的编码表
string res; // 生成的二进制编码字符串
int size = 0; // 所占字节数
int zipSize = 0; // 所占比特数(用于处理末尾数字补全)
};
struct UnZip
{
string originFileName; // 要解压的文件名
string destFileName; // 解压生成的文件名
};
// 将int数组转化为二元组形式,表示各个int数字出现的频率
mapint > getList(int* text, int length);
//自定义排序函数
bool cmp(const Node* node1, const Node* node2);
// 通过二元组创建哈夫曼树
Node* createHafumanTree(vector list) ;
// 获取编码
void getCodes(Node* root, string path, map& encodeMap) ;
// 读取文件内容,得到int数组
elementType* readFile(string fileName, int& size);
// 根据编码表将int数组转化为新的编码
string transform(elementType* buff, int length, map encodeMap) ;
// 获取文件生成的二进制编码字符串
void generateCodes(Zip& zip);
//将传入的二进制字符串转换成十进制,并返回十进制数字
int binToTen(string binaryString);
// 将新编码字符串转化为int数组(转化采用末尾不够补0),减少占用空间,并写入文件中,返回文件比特数,同时一并将编码表和字节与比特数写入
void zipFile(string res, string fileName, int& zipSize, ZipStruct* zipStruct);
//将传入的int转换成二进制字符串
string intToBin(int ch);
// 根据编码表将文件还原
void unZipFile(string originFileName, string destFileName, ZipStruct* zipStruct);
int main()
{
Zip zip;
UnZip unZip;
ZipStruct zipStruct;
zip.originFileName = "D:/test.png";
zip.destFileName = "D:/test.myZip";
generateCodes(zip);
zipStruct.encodeMap = zip.encodeMap;
zipStruct.size = zip.size;
zipFile(zip.res, zip.destFileName, zip.zipSize, &zipStruct);
unZip.originFileName = zip.destFileName;
unZip.destFileName = "D:/test1.png";
unZipFile(unZip.originFileName, unZip.destFileName, &zipStruct);
system("pause");
}
mapint > getList(int* text, int length)
{
mapint> map;
for (int i = 0; i < length; i++)
{
if (map.count((int)text[i]) == 1)
{
map[text[i]] = map[text[i]] + 1;
}
else
{
map[text[i]] = 1;
}
}
return map;
}
bool cmp(const Node* node1, const Node* node2)
{
return node1->value > node2->value;
}
Node* createHafumanTree(vector list)
{
while (list.size() > 1)
{
sort(list.begin(), list.end(), cmp);
Node* left = list.at(list.size() - 1);
Node* right = list.at(list.size() - 2);
Node* node = (Node*)malloc(sizeof(Node));
if (node == NULL)
{
cout << "内存不足" << endl;
return NULL;
}
node->value = left->value + right->value;
node->left = left;
node->right = right;
list.pop_back();
list.pop_back();
list.push_back(node);
}
return list.at(0);
}
void getCodes(Node* root, string path, map& encodeMap)
{
if (root == NULL)
{
return;
}
if (root->left == NULL && root->right == NULL)
{
encodeMap.insert(map::value_type(root->data, path));
}
getCodes(root->left, path + "0", encodeMap);
getCodes(root->right, path + "1", encodeMap);
}
elementType* readFile(string fileName, int& size)
{
struct stat buf;
stat(fileName.c_str(), &buf);
size = buf.st_size;
FILE* fp = NULL;
int* buff = new int[buf.st_size];
errno_t err;
if ((err = fopen_s(&fp, fileName.c_str(), "rb")) != 0)
{
cout << "文件打开失败" << endl;
return NULL;
}
int index = 0;
while (index < buf.st_size)
{
buff[index++] = fgetc(fp);
}
fclose(fp);
return buff;
}
string transform(elementType* buff, int length, map encodeMap)
{
string res = "";
for (int i = 0; i < length; i++)
{
res += encodeMap[buff[i]];
}
return res;
}
void generateCodes(Zip& zip)
{
zip.buff = readFile(zip.originFileName, zip.size);
zip.twoTuple = getList(zip.buff, zip.size);
vector list;
for (auto& it : zip.twoTuple)
{
Node* node = (Node*)malloc(sizeof(Node));
if (node == NULL)
{
cout << "内存不足" << endl;
return;
}
node->data = it.first;
node->value = it.second;
node->left = NULL;
node->right = NULL;
list.push_back(node);
}
Node* root = createHafumanTree(list);
getCodes(root, "", zip.encodeMap);
zip.res = transform(zip.buff, zip.size, zip.encodeMap);
}
int binToTen(string binaryString)
{
int parseBinary = 0;
for (int i = 0; i < binaryString.length(); ++i)
{
if (binaryString[i] == '1')
{
parseBinary += pow(2.0, binaryString.length() - i - 1);
}
}
return parseBinary;
}
void zipFile(string res, string fileName, int& zipSize, ZipStruct* zipStruct)
{
zipSize = res.length();
zipStruct->zipSize = zipSize;
if (res.length() % 8 != 0)
{
for (int i = 0; i < res.length() % 8; i++)
{
res += "0";
}
}
char* bytes = new char[res.length() / 8];
int index = 0;
for (int i = 0; i < res.length();)
{
string subStr = res.substr(i, 8);
i += 8;
bytes[index] = binToTen(subStr);
index++;
}
FILE* fp = NULL;
errno_t err;
if ((err = fopen_s(&fp, fileName.c_str(), "wb")) != 0)
{
cout << "文件写入失败" << endl;
return;
}
fwrite(zipStruct, sizeof(ZipStruct), 1, fp);
fwrite(bytes, sizeof(unsigned __int8), res.length() / 8, fp);
fclose(fp);
}
string intToBin(int ch)
{
string res = "";
for (int i = 7; i >= 0; i--)
{
if (ch & (128 >> 7 - i))
{
res += "1";
}
else
{
res += "0";
}
}
return res;
}
void unZipFile(string originFileName, string destFileName, ZipStruct* zipStruct)
{
FILE* fp = NULL;
errno_t err;
if ((err = fopen_s(&fp, originFileName.c_str(), "rb")) != 0)
{
cout << "文件打开失败" << endl;
return;
}
fread(zipStruct, sizeof(ZipStruct), 1, fp);
map decodeMap;
for (auto& it : zipStruct->encodeMap)
{
decodeMap.insert(mapchar>::value_type(it.second, it.first));
}
// 为了凑整,省的用if语句了
int size = zipStruct->zipSize;
int length = (size + 7) / 8;
int* buff = new int[length];
int index = 0;
while (index < length)
{
buff[index++] = fgetc(fp);
}
fclose(fp);
string res = "";
for (int i = 0; i < length; i++)
{
res += intToBin(buff[i]);
}
string text = "";
for (int i = 0; i <= size;)
{
index = 1;
while (i + index <= size)
{
string temp = res.substr(i, index);
if (decodeMap.count(temp) == 1)
{
text += decodeMap[temp];
break;
}
index++;
}
i += index;
}
if ((err = fopen_s(&fp, destFileName.c_str(), "wb")) != 0)
{
cout << "文件写入失败" << endl;
return;
}
fwrite(text.c_str(), sizeof(unsigned __int8), text.length(), fp);
fclose(fp);
}
文章可能在审核,要过一小会才能看到