实现文件中数据的加解密与压缩:将硬盘上的一个文本文件进行加密,比较加密文件和原始文件的大小差别;对加密文件进行解密,比较原始文件和解码文件的内容是否一致。
代码
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
typedef struct node* LIST;
typedef struct node* TREE;
struct node
{
int high; //高位ascll
int low; //判断是否是中文,低位
int weight;
int code_index; //编码指针
char code[100]; //编码数组
TREE Left;
TREE Right;
LIST NEXT;
};
void insert(LIST head, LIST tmp);
LIST find_and_insert(LIST head, LIST tmp);
void output(LIST head);
LIST init_LIST(int high, int low, int weight);
TREE tree_node_init(int high, int low, int weight);
TREE build_tree(LIST head);
void print_huffman_pre(TREE Tree, int flag);
void update_tree(TREE Tree);
void save_file(TREE* a, int right, TREE Tree);
void to_free_tree(TREE Tree);
void to_free_list(LIST head);
void coding(TREE Tree);
void decoding();
TREE queue[1000];
int queue_index = 0;
int sum_bit_coding = 0;
int sum_bit_decoding = 0;
char file_in[100] = "D:\\file.txt";
char file_out[100];
void init_main();
void update_file_out(char file_in[])
{
int i;
for (i = strlen(file_in) - 1; i >= 0; i--)
if (file_in[i] == '\\')
break;
int j;
for (j = 0; j <= i; j++)
file_out[j] = file_in[j];
}
int main()
{
init_main();
return 0;
}
void init_main()
{
LIST head = init_LIST(0, 0, 0);
FILE* P;
while (1)
{
printf("为了结果的准确性,请输入GBK格式的txt文件\n");
printf("请输入需要执行的文件及路径\n例如\nD:\\file.txt\n");
gets(file_in);
fopen_s(&P,file_in, "r");
if (P == NULL)
{
printf("文件打开失败\n请重新输入\n");
continue;
}
else
{
printf("打开成功\n");
break;
}
}
update_file_out(file_in);
int ch;
while ((ch = fgetc(P)) != EOF)
{
LIST tmp = init_LIST(ch, -1, 1);
if (ch > 128)
tmp->low = fgetc(P);
insert(head, find_and_insert(head, tmp));
}
TREE Tree = build_tree(head);
coding(Tree);
print_huffman_pre(Tree->NEXT, 0);
update_tree(Tree);
queue_index = 0;
print_huffman_pre(Tree->NEXT, 0);
decoding();
fclose(P);
while (1)
{
int flag;
printf("请选择操作命令-> \n \t1:统计信息;\n\t2:词频统计;\n\t3:编码详情;\n\t4:文件输出信息;\n\t5:return\n");
scanf_s("%d", &flag);
switch (flag)
{
case 1:
printf("-----------------------------------\n");
printf("文件已经保存,共写入%d比特\n", sum_bit_coding);
printf("从文件读取%d比特\n", 8 * (Tree->high + Tree->low * 2));
printf("压缩率是%.3f\n", 1.0 * sum_bit_coding / 8 / (Tree->high + Tree->low * 2));
printf("共写入解码文件%d比特\n", sum_bit_decoding);
printf("-----------------------------------\n");
break;
case 2:
output(head);
break;
case 3:
print_huffman_pre(Tree->NEXT, 1);
break;
case 4:
{
char coding_file_name[100];
strcpy_s(coding_file_name, file_out);
strcat_s(coding_file_name, "coding.txt");
char encoding_file_name[100];
strcpy_s(encoding_file_name, file_out);
strcat_s(encoding_file_name, "encoding.txt");
printf("输入文件的路径为%s\n", file_in);
printf("加密文件的路径为%s\n", coding_file_name);
printf("解码文件的路径为%s\n", encoding_file_name);
break;
}
case 5:
return;
}
}
to_free_tree(Tree);
to_free_list(head);
}
void decoding()
{
sum_bit_decoding = 0;
char coding_file_name[100];
strcpy_s(coding_file_name, file_out);
strcat_s(coding_file_name, "coding.txt");
char encoding_file_name[100];
strcpy_s(encoding_file_name, file_out);
strcat_s(encoding_file_name, "encoding.txt");
FILE* in;
fopen_s(&in,coding_file_name, "r");
FILE* out;
fopen_s(&out,encoding_file_name, "wb");
int ch;
int str_index = 0, left;
char str[100];
while ((ch = fgetc(in)) != EOF)
{
str[str_index++] = ch;
str[str_index] = '\0';
for (left = 0; left < queue_index; left++)
{
if (strcmp(queue[left]->code, str) == 0)
{
if (queue[left]->high > 128) sum_bit_decoding += 16;
else sum_bit_decoding += 8;
if ((char)queue[left]->high == '\n')
{
fprintf(out, "\r\n");
}
else
{
fprintf(out, "%c", queue[left]->high);
if (queue[left]->high > 128) fprintf(out, "%c", queue[left]->low);
}
str_index = 0;
break;
}
}
}
fclose(in);
fclose(out);
}
void to_free_list(LIST head)
{
LIST P = head;
while (head->NEXT)
{
P = head->NEXT;
head->NEXT = head->NEXT->NEXT;
free(P);
}
free(head);
}
void to_free_tree(TREE Tree)
{
if (!Tree) return;
to_free_tree(Tree->Left);
to_free_tree(Tree->Right);
free(Tree);
}
void save_file(TREE* a, int right, TREE Tree)
{
int left;
sum_bit_coding = 0;
FILE* P;
fopen_s(&P,file_in, "r");
char coding_file_name[100];
strcpy_s(coding_file_name, file_out);
strcat_s(coding_file_name, "coding.txt");
FILE* out;
fopen_s(&out,coding_file_name, "wb");
if (P == NULL)
printf("文件打开失败\n");
int ch;
while ((ch = fgetc(P)) != EOF)
{
LIST tmp = init_LIST(ch, -1, 1);
if (ch > 128)
tmp->low = fgetc(P);
for (left = 0; left < right; left++)
{
if (a[left]->high == tmp->high)
{
if (tmp->high > 128 && tmp->low == a[left]->low)
{
fprintf(out, "%s", a[left]->code);
sum_bit_coding += strlen(a[left]->code);
}
if (tmp->high <= 128)
{
fprintf(out, "%s", a[left]->code);
sum_bit_coding += strlen(a[left]->code);
}
}
}
free(tmp);
}
fclose(P);
fclose(out);
}
void update_tree(TREE Tree)
{
TREE a[1000];
int left = 0, right = 0;
if (!Tree) return;
a[right++] = Tree->NEXT;
while (left < right)
{
if (a[left]->Left)
{
a[right++] = a[left]->Left;
strcpy_s(a[left]->Left->code, a[left]->code);
a[left]->Left->code_index = strlen(a[left]->code);
a[left]->Left->code[a[left]->Left->code_index++] = '0';
}
if (a[left]->Right)
{
a[right++] = a[left]->Right;
strcpy_s(a[left]->Right->code, a[left]->code);
a[left]->Right->code_index = strlen(a[left]->code);
a[left]->Right->code[a[left]->Right->code_index++] = '1';
}
left++;
}
save_file(a, right, Tree);
}
TREE tree_node_init(int high, int low, int weight)
{
TREE tmp = (TREE)malloc(sizeof(struct node));
tmp->high = high;
tmp->low = low;
tmp->weight = weight;
strcpy_s(tmp->code, "\0");
tmp->code_index = 0;
tmp->Right = NULL;
tmp->Left = NULL;
tmp->NEXT = NULL;
return tmp;
}
TREE build_tree(LIST head)
{
TREE Tree = tree_node_init(head->high, head->low, 0);
TREE T = Tree;
LIST P = head->NEXT;
while (P)
{
T->NEXT = tree_node_init(P->high, P->low, P->weight);
T = T->NEXT;
Tree->weight++;
P = P->NEXT;
}
return Tree;
}
void coding(TREE Tree)
{
while (Tree->weight > 1)
{
TREE t1 = Tree->NEXT;
Tree->NEXT = Tree->NEXT->NEXT;
TREE t2 = Tree->NEXT;
Tree->NEXT = Tree->NEXT->NEXT;
TREE t = tree_node_init(-1, -1, t1->weight + t2->weight);
t->Left = t1;
t->Right = t2;
insert(Tree, t);
Tree->weight--;
}
}
void print_huffman_pre(TREE Tree, int flag)
{
if (!Tree) return;
if ((char)Tree->high == '\n')
{
queue[queue_index++] = Tree;
if (flag)
printf("\\n weight == %d coding = %s\n", Tree->weight, Tree->code);
}
else if (Tree->high > 128)
{
queue[queue_index++] = Tree;
if (flag)
{
putchar(Tree->high);
putchar(Tree->low);
printf(" weight == %d coding = %s\n", Tree->weight, Tree->code);
}
}
else if (Tree->high != -1)
{
queue[queue_index++] = Tree;
if (flag)
{
putchar(Tree->high);
printf(" weight == %d coding = %s\n", Tree->weight, Tree->code);
}
}
print_huffman_pre(Tree->Left, flag);
print_huffman_pre(Tree->Right, flag);
}
LIST find_and_insert(LIST head, LIST tmp)
{
if (tmp->low != -1) head->low++;
else head->high++;
LIST P = head;
while (P->NEXT)
{
if (P->NEXT->high == tmp->high)
{
if (P->NEXT->low != -1 && tmp->low != -1 && P->NEXT->low == tmp->low)
{
LIST found = init_LIST(P->NEXT->high, P->NEXT->low, P->NEXT->weight + 1);
LIST del = P->NEXT;
P->NEXT = P->NEXT->NEXT;
del->NEXT = NULL;
free(del);
return found;
}
if (P->NEXT->low == -1 && tmp->low == -1)
{
LIST found = init_LIST(P->NEXT->high, P->NEXT->low, P->NEXT->weight + 1);
LIST del = P->NEXT;
P->NEXT = P->NEXT->NEXT;
del->NEXT = NULL;
free(del);
return found;
}
}
P = P->NEXT;
}
return tmp;
}
void insert(LIST head, LIST tmp)
{
LIST P = head;
while (P->NEXT)
{
if (tmp->weight < P->NEXT->weight)
break;
P = P->NEXT;
}
if (!P->NEXT)
{
P->NEXT = tmp;
return;
}
tmp->NEXT = P->NEXT;
P->NEXT = tmp;
}
void output(LIST head)
{
LIST P = head->NEXT;
while (P)
{
if ((char)P->high == '\n')
{
printf("字符 \\n 个数是%d\t占用字节为%d\t总字节为%d\n", P->weight, P->low == -1 ? 1 : 2, P->weight * (P->low == -1 ? 1 : 2));
P = P->NEXT;
continue;
}
printf("字符 ");
putchar(P->high);
if (P->high > 128)
putchar(P->low);
printf(" 个数是%d\t占用字节为%d\t总字节为%d\n", P->weight, P->low == -1 ? 1 : 2, P->weight * (P->low == -1 ? 1 : 2));
P = P->NEXT;
}
printf("总字节数为%d\n", head->high + head->low * 2);
}
LIST init_LIST(int high, int low, int weight)
{
LIST tmp = (LIST)malloc(sizeof(struct node));
tmp->high = high;
tmp->low = low;
tmp->weight = weight;
tmp->NEXT = NULL;
return tmp;
}
运行效果
创建文件格式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OqNAERp5-1720826856997)(https://i-blog.csdnimg.cn/direct/a85d2fb516044620aa0d8273b38737ed.png)]
输入1统计文件信息:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-keSOVIqm-1720826856999)(https://i-blog.csdnimg.cn/direct/d60d534258704ca3a503eaa9ee2d573c.png)]
输入2进行词频统计:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hhUF46o-1720826857000)(https://i-blog.csdnimg.cn/direct/5397ebd0e8cf4f4991bdf95b6370c66a.png)]
输入3查看编码详情:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpjukLkB-1720826857000)(https://i-blog.csdnimg.cn/direct/7fe56a66b63848dc949da15b26c27cc9.png)]
输入4文件输出信息:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PzG2J9n4-1720826857001)(https://i-blog.csdnimg.cn/direct/85fb4de64c1e4d9c9dadb1f9a9b703e1.png)]
输入5return:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SkL6rM7B-1720826857001)(https://i-blog.csdnimg.cn/direct/0c680dd78de547c3b62f1d5457c1d68e.png)]
完整步骤:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdVn5N0V-1720826857002)(https://i-blog.csdnimg.cn/direct/8a7702ee10da4643b12bede5ed97c102.png)]