用C语言实现实现文件中数据的加解密与压缩:将硬盘上的一个文本文件进行加密,比较加密文件和原始文件的大小差别;对加密文件进行解密,比较原始文件和解码文件的内容是否一致。实验要求:提取原始文件中的数据(包括中文、英文或其他字符),根据数据出现的频率为权重,构建Huffman编码表; 根据Huffman编码表对原始文件进行加密,得到加密文件并保存到硬盘上; 将加密文件进行解密,得到解码文件并保存点硬盘上; 比对原始文件和解码文件的一致性,得出是否一致的结论。
时间: 2023-06-14 11:04:10 浏览: 111
这是一个比较复杂的任务,需要用到多种算法和数据结构。以下是一个较为简单的实现思路:
1. 读取原始文件中的数据,根据出现的频率构建Huffman编码树;
2. 根据Huffman编码树对原始文件进行编码,生成加密文件;
3. 将加密文件存储到硬盘上;
4. 读取加密文件,根据Huffman编码树进行解码,生成解码文件;
5. 将解码文件存储到硬盘上;
6. 比较原始文件和解码文件的内容是否一致。
下面是一个C语言实现的简单例子:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义Huffman树节点
typedef struct TreeNode {
unsigned char data; // 数据
int weight; // 权重
struct TreeNode *left; // 左子节点
struct TreeNode *right;// 右子节点
} TreeNode;
// 定义Huffman编码表节点
typedef struct CodeNode {
unsigned char data; // 数据
char *code; // 编码
} CodeNode;
// 统计字符出现频率
int *getCharFrequency(char *filename, int *len) {
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
printf("Error: Cannot open file: %s\n", filename);
exit(1);
}
int *freq = (int *)calloc(256, sizeof(int));
unsigned char ch;
*len = 0;
while (fread(&ch, sizeof(unsigned char), 1, fp) == 1) {
freq[ch]++;
(*len)++;
}
fclose(fp);
return freq;
}
// 构建Huffman树
TreeNode *buildHuffmanTree(int *freq) {
// 创建节点列表,存储每个字符和它的权重
TreeNode **nodes = (TreeNode **)malloc(256 * sizeof(TreeNode *));
int i, j, k = 0;
for (i = 0; i < 256; i++) {
if (freq[i] > 0) {
nodes[k] = (TreeNode *)malloc(sizeof(TreeNode));
nodes[k]->data = (unsigned char)i;
nodes[k]->weight = freq[i];
nodes[k]->left = NULL;
nodes[k]->right = NULL;
k++;
}
}
// 构建Huffman树
while (k > 1) {
// 找出权重最小的两个节点
int min1 = 0, min2 = 1;
if (nodes[min1]->weight > nodes[min2]->weight) {
int tmp = min1;
min1 = min2;
min2 = tmp;
}
for (i = 2; i < k; i++) {
if (nodes[i]->weight < nodes[min1]->weight) {
min2 = min1;
min1 = i;
} else if (nodes[i]->weight < nodes[min2]->weight) {
min2 = i;
}
}
// 将这两个节点合并为一个节点
TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));
newNode->data = 0;
newNode->weight = nodes[min1]->weight + nodes[min2]->weight;
newNode->left = nodes[min1];
newNode->right = nodes[min2];
// 从节点列表中删除这两个节点,加入新节点
nodes[min1] = newNode;
nodes[min2] = nodes[k-1];
k--;
}
// 返回Huffman树的根节点
TreeNode *root = nodes[0];
free(nodes);
return root;
}
// 生成Huffman编码表
CodeNode *buildHuffmanCodeTable(TreeNode *root) {
CodeNode *table = (CodeNode *)malloc(256 * sizeof(CodeNode));
char *code = (char *)malloc(256 * sizeof(char));
code[0] = '\0';
buildHuffmanCodeTableHelper(root, table, code);
free(code);
return table;
}
void buildHuffmanCodeTableHelper(TreeNode *node, CodeNode *table, char *code) {
if (node->left == NULL && node->right == NULL) {
// 叶子节点,存储编码
table[node->data].data = node->data;
table[node->data].code = (char *)malloc(strlen(code) + 1);
strcpy(table[node->data].code, code);
} else {
// 非叶子节点,继续遍历
int len = strlen(code);
char *leftCode = (char *)malloc(len + 2);
strcpy(leftCode, code);
leftCode[len] = '0';
leftCode[len+1] = '\0';
buildHuffmanCodeTableHelper(node->left, table, leftCode);
free(leftCode);
char *rightCode = (char *)malloc(len + 2);
strcpy(rightCode, code);
rightCode[len] = '1';
rightCode[len+1] = '\0';
buildHuffmanCodeTableHelper(node->right, table, rightCode);
free(rightCode);
}
}
// 将原始文件编码为Huffman编码
char *encodeWithHuffman(char *filename, CodeNode *table, int len, int *encodedLen) {
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
printf("Error: Cannot open file: %s\n", filename);
exit(1);
}
// 计算编码后的长度
int i;
*encodedLen = 0;
unsigned char ch;
while (fread(&ch, sizeof(unsigned char), 1, fp) == 1) {
*encodedLen += strlen(table[ch].code);
}
// 分配空间存储编码后的数据
char *encoded = (char *)malloc((*encodedLen/8 + 1) * sizeof(char));
encoded[0] = '\0';
// 重新读取原始文件,将每个字符编码后拼接起来
fseek(fp, 0, SEEK_SET);
while (fread(&ch, sizeof(unsigned char), 1, fp) == 1) {
strcat(encoded, table[ch].code);
}
fclose(fp);
return encoded;
}
// 将Huffman编码解码为原始数据
unsigned char *decodeWithHuffman(char *encoded, TreeNode *root, int len, int *decodedLen) {
// 分配空间存储解码后的数据
unsigned char *decoded = (unsigned char *)malloc(len * sizeof(unsigned char));
decoded[0] = '\0';
int pos = 0;
// 按照Huffman编码逐位解码
TreeNode *p = root;
int i;
for (i = 0; i < strlen(encoded); i++) {
if (encoded[i] == '0') {
p = p->left;
} else if (encoded[i] == '1') {
p = p->right;
}
if (p->left == NULL && p->right == NULL) {
decoded[pos++] = p->data;
p = root;
}
}
*decodedLen = pos;
return decoded;
}
// 将数据写入文件
void writeToFile(char *filename, void *data, int len) {
FILE *fp = fopen(filename, "wb");
if (fp == NULL) {
printf("Error: Cannot open file: %s\n", filename);
exit(1);
}
fwrite(data, len, 1, fp);
fclose(fp);
}
int main() {
char *filename = "test.txt";
// 统计字符出现频率
int len;
int *freq = getCharFrequency(filename, &len);
// 构建Huffman编码表
TreeNode *root = buildHuffmanTree(freq);
CodeNode *table = buildHuffmanCodeTable(root);
// 将原始文件编码为Huffman编码
int encodedLen;
char *encoded = encodeWithHuffman(filename, table, len, &encodedLen);
// 将编码后的数据写入文件
writeToFile("test.huff", encoded, (encodedLen/8 + 1) * sizeof(char));
// 读取编码后的数据,进行解码
FILE *fp = fopen("test.huff", "rb");
if (fp == NULL) {
printf("Error: Cannot open file: test.huff\n");
exit(1);
}
fseek(fp, 0, SEEK_END);
int fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *encoded2 = (char *)malloc(fileSize * sizeof(char));
fread(encoded2, sizeof(char), fileSize, fp);
fclose(fp);
int decodedLen;
unsigned char *decoded = decodeWithHuffman(encoded2, root, len, &decodedLen);
// 将解码后的数据写入文件
writeToFile("test_decoded.txt", decoded, decodedLen * sizeof(unsigned char));
// 比较原始文件和解码文件的内容是否一致
fp = fopen(filename, "rb");
FILE *fp2 = fopen("test_decoded.txt", "rb");
unsigned char ch1, ch2;
int isEqual = 1;
while (fread(&ch1, sizeof(unsigned char), 1, fp) == 1 && fread(&ch2, sizeof(unsigned char), 1, fp2) == 1) {
if (ch1 != ch2) {
isEqual = 0;
break;
}
}
if (isEqual) {
printf("The original file and decoded file are the same.\n");
} else {
printf("The original file and decoded file are different.\n");
}
// 释放内存
free(freq);
free(encoded);
free(encoded2);
free(decoded);
for (int i = 0; i < 256; i++) {
if (table[i].code != NULL) {
free(table[i].code);
}
}
free(table);
return 0;
}
```
这个例子中,我们首先统计了原始文件中每个字符出现的频率,然后根据频率构建了Huffman编码树,并生成了Huffman编码表。接下来,我们将原始文件中的数据编码为Huffman编码,并将编码结果保存到硬盘上。然后,我们读取编码文件,对其进行解码,得到原始数据,并将解码结果保存到硬盘上。最后,我们比较原始文件和解码文件的内容是否一致。
需要注意的是,这个例子中只是实现了一个简单的Huffman编码算法,并没有对数据进行实际的加密,如果需要进行加密,可以将编码后的数据进行进一步处理,例如进行异或运算或置换等操作。
阅读全文