GTK+和C语言实现的哈夫曼文件压缩工具
来源:互联网 发布:云计算 搭建 openstack 编辑:程序博客网 时间:2024/05/17 01:54
/************************************************************************* > File Name: compressor.c > Author: hepan > Mail: hepan@xiyoulinux.org > Created Time: 2016年12月23日 星期五 11时15分00秒 ************************************************************************/#include <gtk/gtk.h>#include <gdk/gdk.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <time.h>#include <pthread.h>#define MAXLEN 256 //文件名最大长度#define INFINITY 2147483647 //Long的最大值//long file_len;//float read_len = 0.0, write_len = 0.0;long sumlength, FileLength, FileLength1; //记录源文件和压缩文件的长度float rate, speed; //记录压缩率和速度double duration; //记录压缩用时int flag; //判断文件是否压缩解压完成typedef struct { unsigned char ch; //记录不同字符在数组中的位置 long weight; //字符出现频率(权值) long parent, lchild, rchild; //定义哈夫曼树指针变量 char code[MAXLEN]; //定义存储哈夫曼编码的数组 int CodeLength; //编码长度} HuffNode, HuffmanTree[512];//将窗体独立成一个结构体struct widget { GtkWidget *window; GtkWidget *window1; GtkWidget *window2; GtkWidget *label_tips; GtkWidget *button_cancel; GtkWidget *entry; GtkWidget *entry1; GtkWidget *entry2; GtkWidget *pbar; GtkWidget *text1; GtkWidget *text2; GtkWidget *vbox; GtkWidget *hbox_button; int timer;} wgt;void compressor(); //哈夫曼压缩器图形主界面void *compress(void *arg); //压缩函数void *decompress(void *arg); //解压函数void complete_compress(); //压缩完成,打印压缩信息void complete_decompress(); //解压完成,打印解压信息void choose_file1(GtkWidget *widget, gpointer data); //选择压缩文件函数void file_compress(GtkWidget *widget,gpointer data); //文件压缩窗口void choose_file2(GtkWidget *widget,gpointer data); //选择解压文件函数void file_decompress(GtkWidget *widget,gpointer data); //文件解压窗口void send_file(GtkWidget *widget, gpointer data); void file_ok_sel(GtkWidget *w, GtkFileSelection *fs);void gtk_dialog_destroy(GtkWidget *widget, gpointer data); //窗口销毁函数void my_err(const char *err_string, int line); //错误处理函数int my_itoa(int val, char* buf, int r); //整型值转r进制字符串函数void Select(HuffmanTree ht, int pos, int *s1, int *s2); //建立哈弗曼树中用于选择最小和次小权值结点的函数void hfmcoding(HuffmanTree ht,int n); //哈夫曼编码函数gboolean update_progress_bar_compress(gpointer data); //压缩进度条更新函数gboolean update_progress_bar_decompress(gpointer data); //解压缩进度条更新函数gint progress_timeout(gpointer data); //进度条循环函数void destroy_progress(GtkWidget *widget, struct widget *pdata); // 清除分配的内存,删除定时器(timer) GtkTextBuffer *text_buffer; //文本框缓冲区char pathname[MAXLEN]; //保存文件的绝对路径名//建立哈弗曼树中用于选择最小和次小权值结点的函数void Select(HuffmanTree ht, int pos, int *s1, int *s2){ //m1存放最小权值,m2存放次小权值 //s1存放m1在数组中的下标,s2存放m2在数组中的下标 int i, j; long m1, m2; m1 = m2 = INFINITY; for (j=0; j <= pos; j++) { if (ht[j].weight < m1 && ht[j].parent == -1) { m2 = m1; *s2 = *s1; *s1 = j; m1 = ht[j].weight; } else if (ht[j].weight < m2 && ht[j].parent == -1) { m2 = ht[j].weight; *s2 = j; } } //使 s1 小于 s2 if (*s1 > *s2) { i = *s1; *s1 = *s2; *s2 = i; }}//哈弗曼编码函数void hfmcoding(HuffmanTree ht, int n){ //从叶子向根求每个字符的哈弗曼编码 int start; int i, f, c; char codes[MAXLEN]; codes[n-1] = '\0'; //编码结束符 for (i=0; i<n; i++) { //逐个字符求哈弗曼编码 start = n - 1; for (c=i,f=ht[i].parent; f != -1; c=f,f=ht[f].parent) { start--; if (ht[f].lchild == c) { codes[start] = '0'; } else { codes[start] = '1'; } } strcpy(ht[i].code,&codes[start]); ht[i].CodeLength = strlen(ht[i].code); }}//压缩函数void *compress(void *arg) { int i, j; FILE *ifp, *ofp; HuffmanTree ht; unsigned char c; int n, m; //叶子数和结点数 int s1, s2; //权值最小的两个结点的标号 char buf[MAXLEN], name[MAXLEN]; char codes[MAXLEN]; long filelength = 0; int count = 0; clock_t start1, start2, finish1, finish2; double duration1, duration2; ifp = fopen(pathname,"rb"); if (ifp == NULL) { my_err("fopen",__LINE__); } bzero(buf,sizeof(buf)); bzero(name,sizeof(name)); for (i=0,j=0; i < strlen(pathname); i++) { if (pathname[i] == '/') { j = 0; continue; } name[j++] = pathname[i]; } name[j] = '\0'; for (i=0; i<strlen(name); i++) { if (name[i] == '.') { break; } } strncpy(buf, name, i); //printf("\n-->%s",buf); ofp = fopen(strcat(buf,".code"),"wb"); if (ofp==NULL) { my_err("fopen",__LINE__); } start1 = clock() ; //开始计时1 FileLength = 0; while (!feof(ifp)) { fread(&c,1,1,ifp); ht[c].weight++; FileLength++; //printf("字符 %c : %ld 个; ", c, ht[c].weight); } FileLength--; ht[c].weight--; //再将ASCII转换为字符存入到结点的ch成员里,同时给双亲、孩子赋初值-1 n = 0; for (i=0; i<256; i++) { if (ht[i].weight != 0) { //printf("\n****<>****%ld",ht[i].weight); ht[i].ch = (unsigned char)i; n++; //叶子数 ht[i].lchild = -1; ht[i].rchild = -1; ht[i].parent = -1; } } m = 2 * n - 1; //哈弗曼树结点总数 j = 0; for (i=0; i<256; i++) { //去掉权值为0的结点 if (ht[i].weight != 0) { ht[j] = ht[i]; j++; } } for (i=n; i<m; i++) { //初始化根结点 ht[i].lchild = -1; ht[i].rchild = -1; ht[i].parent = -1; } //建立哈弗曼树 for (i=n; i<m; i++) { Select(ht,i-1,&s1,&s2); ht[i].lchild = s1; ht[i].rchild = s2; ht[s1].parent = i; ht[s2].parent = i; ht[i].weight = ht[s1].weight + ht[s2].weight; //printf("\n---->s1 = %d, \ts2 = %d", s1, s2); //printf("\n****>w1 = %ld, \tw2 = %ld, \tsum = %ld", ht[s1].weight, ht[s2].weight, ht[i].weight); } hfmcoding(ht,n); finish1 = clock(); duration1 = (double)(finish1 - start1) / CLOCKS_PER_SEC; // printf( "哈弗曼树编码用时为:%f seconds\n", duration1 ); // printf("叶子数为%d,结点数为%d\n",n,m); // for(i=0;i<n;i++) { // printf("%d号叶子结点的权值为:%ld,双亲为:%d,左右孩子:%d,编码为:%s\n", // i,ht[i].weight,ht[i].parent,ht[i].lchild,ht[i].code); // } start2 = clock() ; //开始计时2 fseek(ifp,0,SEEK_SET); //将ifp指针移到文件开头位置 fwrite(&FileLength,4,1,ofp); //将FileLength写入目标文件的前4个字节的位置 fseek(ofp,8,SEEK_SET); //再将目标文件指针ofp移到距文件开头8个字节位置 codes[0] = 0; //将编码信息写入目标文件 while (!feof(ifp)) { //fread(&c,1,1,ifp); c = fgetc(ifp); filelength++; for (i=0; i<n; i++) { if (c == ht[i].ch) { break; } } strcat(codes,ht[i].code); c = 0; while (strlen(codes) >= 8) { //printf("\nbefore : c = %d", c); //printf("\ncodes: >>%s",codes); for (i=0; i<8; i++) { //将codes的前8位01代码表示的字符存入c //printf("\n------->%c",codes[i]); if (codes[i] == '1') { c = (c << 1) | 1; //printf("\n<?*?>%d",c); } else { c = c << 1; //printf("\n<?-^-?>%d",c); } } //printf("\nafter: c = %d",c); fwrite(&c,1,1,ofp); //将新的字符写入目标文件 sumlength++; strcpy(codes,codes+8); //更新codes的值 } if (filelength == FileLength) { break; } } //再将剩余的不足8位的01代码补全8位,继续写入 if (strlen(codes) > 0) { strcat(codes,"00000000"); for (i=0; i<8; i++) { if (codes[i] == '1') { c = (c << 1) | 1; } else { c = c << 1; } } fwrite(&c,1,1,ofp); sumlength++; } sumlength += 8; //printf("编码区总长为:%ld个字节\n",sumlength-8); //将sumlength和n的值写入目标文件,为的是方便解压 fseek(ofp,4,SEEK_SET); fwrite(&sumlength,4,1,ofp); //把sumlength写进目标文件的第5-8个字节里 fseek(ofp,sumlength,SEEK_SET); fwrite(&n,4,1,ofp); //把叶子数n写进编码段后面的4个字节的位置 //存储方式为:n*(字符值(1个字节)+该字符的01编码的位数(1个字节)+编码(字节数不确定,用count来计算总值)) for (i=0; i<n; i++) { fwrite(&(ht[i].ch),1,1,ofp); c = ht[i].CodeLength; //编码最长为MAXLEN位,因此只需用一个字节存储 //printf("\n---->%d",c); //printf("\n---->%s",ht[i].code); fwrite(&c,1,1,ofp); //写入字符的编码 if (ht[i].CodeLength % 8 != 0) { for (j = ht[i].CodeLength % 8; j < 8; j++) { //把编码不足8位的在低位补0,赋值给C,再把C写入 strcat(ht[i].code,"0"); } } while (ht[i].code[0] != 0) { //开始存入编码,每8位二进制数存入一个字节 c = 0; for (j=0; j<8; j++) { if (ht[i].code[j] == '1') { c = (c << 1) | 1; } else { c = c << 1; } } //printf("\n***>%s",ht[i].code); strcpy(ht[i].code,ht[i].code+8); //编码前移8位,继续存入编码 //printf("\n--->%s",ht[i].code); count++; //编码占的字节数的总值 //printf("\n---->%d",count); fwrite(&c,1,1,ofp); } } sumlength = sumlength + 4 + n * 2 + count; //计算压缩后文件的长度 //printf("\nafter compress: %ld Byte\n", sumlength); finish2 = clock(); duration2 = (double)(finish2- start2) / CLOCKS_PER_SEC; duration = duration1 + duration2; /*printf( "写入目标文件用时为:%f seconds\n", duration2);*/ //printf( "压缩用时为:%f seconds\n", duration1+duration2); speed = (float)FileLength/(duration1+duration2)/1000; //printf("\n压缩速率为:%5.4f KB/S\n",speed); //printf("源文件长度为:%ld Byte\n",FileLength); rate = (float)sumlength / (float)FileLength; //printf("压缩率(百分比)为:%4.2f%%\n",rate*100); flag = 1; complete_compress(); fclose(ifp); fclose(ofp); pthread_exit(0);}//整型值转r进制字符串函数int my_itoa(int val, char* buf, int r){ const unsigned int radix = r; char* p; unsigned int a; //every digit int len; char* b; //start of the digit char char temp; unsigned int u; p = buf; if (val < 0) { *p++ = '-'; val = 0 - val; } u = (unsigned int)val; b = p; do { a = u % radix; u /= radix; *p++ = a + '0'; } while (u > 0); len = (int)(p - buf); *p-- = 0; //swap do { temp = *p; *p = *b; *b = temp; --p; ++b; } while (b < p); return len;}//解压缩void *decompress(void *arg){ HuffmanTree ht; clock_t start, finish; FILE *ifp, *ofp; long filelength; int n, m; int i, j, k; char buf[MAXLEN], codes[MAXLEN]; char buffer[MAXLEN], name[MAXLEN]; unsigned char c; int maxlength; ifp = fopen(pathname,"rb"); if (ifp == NULL) { my_err("fopen",__LINE__); } bzero(buf,sizeof(buffer)); bzero(name,sizeof(name)); for (i=0,j=0; i < strlen(pathname); i++) { if (pathname[i] == '/') { j = 0; continue; } name[j++] = pathname[i]; } name[j] = '\0'; for (i=0; i<strlen(name); i++) { if (name[i] == '.') { break; } } strncpy(buffer, name, i); ofp = fopen(strcat(buffer,".decode"),"wb"); if (ofp==NULL) { my_err("fopen",__LINE__); } start = clock() ; //开始计时 fread(&FileLength,4,1,ifp); //从压缩文件读出FileLength、sumlength //printf("\n源文件为 %ld Byte",FileLength); fread(&sumlength,4,1,ifp); //printf("\n压缩文件为 %ld Byte",sumlength); fseek(ifp,sumlength,SEEK_SET); //利用sumlength读出n的值 fread(&n,4,1,ifp); //printf("\n解码信息:源文件长度为%d个字节,字符种类n=%d\n",FileLength,n); for (i=0; i<n; i++) { //读结点信息 fread(&ht[i].ch,1,1,ifp); //字符 //printf("\n***>%d",ht[i].ch); fread(&c,1,1,ifp); //编码长度 //printf("\n--->%d",c); ht[i].CodeLength = c; ht[i].code[0] = 0; if (ht[i].CodeLength % 8 > 0) { m = ht[i].CodeLength / 8 + 1; //m为编码占的字节数 } else { m = ht[i].CodeLength / 8; } for (j=0; j<m; j++) { //根据字节长度m读出编码 fread(&c,1,1,ifp); //此处c为01编码转换成的字符 my_itoa(c,buf,2); //字符型编码转换成二进制型(首位为1) //如果编码不够8位,则说明缺少了8-k位0,因此应先在前面空缺位写0 for (k=8; k>strlen(buf); k--) { strcat(ht[i].code,"0"); } //再把二进制编码存进ht.code中 strcat(ht[i].code,buf); //printf("\n----->%s",ht[i].code); } ht[i].code[ht[i].CodeLength] = 0; //去掉编码中多余的0 } //找出编码长度的最大值 maxlength = 0; for (i=0; i<n; i++) { if (ht[i].CodeLength > maxlength) { maxlength = ht[i].CodeLength; } } //开始写入目标文件 fseek(ifp,8,SEEK_SET); //指针指向编码区,开始解码 filelength = 0; codes[0] = 0; buf[0] = 0; while (1) { //codes小于编码长度的最大值时,继续读码 while (strlen(codes) < maxlength) { fread(&c,1,1,ifp); //printf("\n----->%d",c); my_itoa(c,buf,2); //还原编码 for (k=8; k>strlen(buf); k--) { strcat(codes,"0"); //把缺掉的0补上 } strcat(codes,buf); //codes中此时存的为一串01编码 } for (i=0; i<n; i++) { //在codes中查找能使其前weight位和ht.code相同的i值,weight即为codelength if (memcmp(ht[i].code,codes,(unsigned int)ht[i].CodeLength) == 0) { break; } } strcpy(codes,codes+ht[i].CodeLength); //更新codes的值 c = ht[i].ch; fwrite(&c,1,1,ofp); filelength++; if (filelength == FileLength) { break; //写入结束 } } finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; //printf( "\n解压完成,解压用时为:%f seconds\n", duration ); fseek(ifp,0,SEEK_SET); while (!feof(ifp)) { fread(&c,1,1,ifp); FileLength1++; } FileLength1--; speed = (float)FileLength/duration/1000; //printf("此文件长度为:%ld Byte\n",FileLength); //printf("\n解压速度为:%5.4f KB/S\n",speed); flag = 1; complete_decompress(); fclose(ifp); fclose(ofp);}//错误处理函数void my_err(const char *err_string, int line){ fprintf(stderr, "line: %d ",line); perror(err_string); exit(1);}//窗口销毁函数void gtk_dialog_destroy(GtkWidget *widget, gpointer data){ gtk_widget_destroy((GtkWidget *)data);}/*//压缩进度条更新函数gboolean update_progress_bar_compress(gpointer data){ FILE *fp = NULL; char buff[8] = {0}; long size = 351920; unsigned char *pbuff; GtkProgressBar *pbar = (GtkProgressBar *)data; if((fp = fopen(pathname,"r")) == NULL) { my_err("fopen",__LINE__); } fseek(fp,0,SEEK_END); file_len = ftell(fp); pbuff = (unsigned char *)malloc((size+1)*sizeof(unsigned char)); memset(pbuff,0,size*sizeof(unsigned char)); if(read_len <= file_len) { fseek(fp,(long int)read_len,SEEK_SET); fread(pbuff,sizeof(unsigned char),size,fp); // fwrite(pbuff,size*sizeof(unsigned char),1,fp); gtk_progress_bar_set_fraction(pbar, read_len / file_len); sprintf(buff,"%d%s",(int)((read_len / file_len) * 100),"%"); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pbar),buff); read_len += size; return TRUE; //必须返回TRUE; } if(read_len > file_len) { gtk_widget_hide(wgt.window1); return TRUE; } fclose(fp); free(pbuff); return TRUE; //必须返回TRUE;}//解压缩进度条更新函数gboolean update_progress_bar_decompress(gpointer data){ FILE *fp = NULL; char buff[8] = {0}; long size = 61097; unsigned char *pbuff; GtkProgressBar *pbar = (GtkProgressBar *)data; if((fp = fopen(pathname,"r")) == NULL) { my_err("fopen",__LINE__); } fseek(fp,0,SEEK_END); file_len = ftell(fp); pbuff = (unsigned char *)malloc((size+1)*sizeof(unsigned char)); memset(pbuff,0,size*sizeof(unsigned char)); if(write_len <= file_len) { fseek(fp,(long int)write_len,SEEK_SET); fread(pbuff,sizeof(unsigned char),size,fp); gtk_progress_bar_set_fraction(pbar,write_len/file_len); sprintf(buff,"%d%s",(int)((write_len/file_len)*100),"%"); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pbar),buff); write_len += size; return TRUE; //必须返回TRUE; } if(write_len > file_len) { gtk_widget_hide(wgt.window1); return TRUE; } complete_compress(); fclose(fp); free(pbuff); return TRUE; //必须返回TRUE;}*///进度条循环函数gint progress_timeout(gpointer data){ struct widget *pdata = (struct widget *)data; gdouble new_val; //使用在调整对象中设置的取值范围计算进度条的值 new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(pdata->pbar)) + 0.2; if (new_val > 1.0) { new_val = 0.0; } //设置进度条的新值 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR (pdata->pbar),new_val); if (flag == 1) { //gtk_widget_hide(pdata->window1); destroy_progress(pdata->window1,pdata); return TRUE; } //这是一个timeout函数,返回 TRUE,这样它就能够继续被调用 return TRUE; }//清除分配的内存,删除定时器(timer) void destroy_progress(GtkWidget *widget, struct widget *pdata) { gtk_timeout_remove(pdata->timer); pdata->timer = 0; pdata->window = NULL; g_free (pdata); gtk_widget_hide(pdata->window1);} //哈夫曼压缩器图形主界面void compressor(){ GtkWidget *window; GtkWidget *button1; GtkWidget *button2; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *image; GdkColor color1; GdkColor color2; gdk_color_parse("LawnGreen",&color1); gdk_color_parse("DarkMagenta",&color2); gtk_widget_hide(wgt.window); image = gtk_image_new_from_file("file.jpg"); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 150, 70); gtk_container_set_border_width(GTK_CONTAINER(window),10); gtk_window_set_title(GTK_WINDOW(window),"Compress"); gtk_window_set_resizable(GTK_WINDOW(window),TRUE); hbox = gtk_hbox_new(FALSE,20); vbox = gtk_vbox_new(FALSE,20); button1 = gtk_button_new_with_label("压缩"); button2 = gtk_button_new_with_label("解压"); gtk_widget_modify_fg(GTK_BIN(button1)->child,GTK_STATE_PRELIGHT,&color1); gtk_widget_modify_fg(GTK_BIN(button2)->child,GTK_STATE_PRELIGHT,&color2); gtk_widget_modify_bg(button1, GTK_STATE_PRELIGHT, &color1); gtk_widget_modify_bg(button2, GTK_STATE_PRELIGHT, &color2); gtk_box_pack_start(GTK_BOX(vbox),image,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(hbox),button1,FALSE,FALSE,10); gtk_box_pack_end(GTK_BOX(hbox),button2,FALSE,FALSE,10); gtk_container_add(GTK_CONTAINER(vbox),hbox); gtk_container_add(GTK_CONTAINER(window),vbox); gtk_widget_show_all(window); g_signal_connect(GTK_OBJECT(button1),"clicked",GTK_SIGNAL_FUNC(choose_file1),(void *)window); g_signal_connect(GTK_OBJECT(button2),"clicked",GTK_SIGNAL_FUNC(choose_file2),(void *)window); g_signal_connect(GTK_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(gtk_main_quit),NULL); gtk_widget_show_all(window);}//选择压缩文件函数void choose_file1(GtkWidget *widget, gpointer data){ GtkWidget *scroll_box; GtkWidget *hbox; GtkWidget *button1; GtkWidget *button2; GtkWidget *button3; GtkWidget *tmp; GtkWidget *label; GdkColor color1; GdkColor color2; GdkColor color3; GdkColor color4; gdk_color_parse("DarkBlue",&color1); gdk_color_parse("LawnGreen",&color2); gdk_color_parse("gray",&color3); gdk_color_parse("red",&color4); tmp = (GtkWidget *)data; gtk_widget_hide(tmp); wgt.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(wgt.window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(wgt.window), 400, 150); gtk_container_set_border_width(GTK_CONTAINER(wgt.window),10); gtk_window_set_title(GTK_WINDOW(wgt.window),"文件压缩"); gtk_window_set_resizable(GTK_WINDOW(wgt.window),TRUE); wgt.vbox = gtk_vbox_new(FALSE,20); hbox = gtk_hbox_new(FALSE,20); scroll_box = gtk_scrolled_window_new(NULL,NULL); wgt.text1 = gtk_text_view_new(); gtk_widget_modify_base(wgt.text1, GTK_STATE_NORMAL, &color3); gtk_widget_modify_text(wgt.text1, GTK_STATE_NORMAL, &color1); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_box), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(scroll_box), wgt.text1); gtk_widget_set_size_request(scroll_box,390,50); button1 = gtk_button_new_with_label("选择文件"); button2 = gtk_button_new_with_label("确认压缩"); button3 = gtk_button_new_with_label("取消压缩"); label = gtk_label_new("待压缩文件位置"); gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color1); gtk_widget_modify_fg(GTK_BIN(button1)->child,GTK_STATE_PRELIGHT,&color1); gtk_widget_modify_fg(GTK_BIN(button2)->child,GTK_STATE_PRELIGHT,&color2); gtk_widget_modify_fg(GTK_BIN(button3)->child,GTK_STATE_PRELIGHT,&color4); //gtk_widget_modify_bg(button1, GTK_STATE_PRELIGHT, &color1); //gtk_widget_modify_bg(button2, GTK_STATE_PRELIGHT, &color2); //gtk_widget_modify_bg(button3, GTK_STATE_PRELIGHT, &color3); gtk_box_pack_start(GTK_BOX(wgt.vbox),button1,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(wgt.vbox),label,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(wgt.vbox),scroll_box,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(hbox),button2,FALSE,FALSE,10); gtk_box_pack_end(GTK_BOX(hbox),button3,FALSE,FALSE,10); gtk_container_add(GTK_CONTAINER(wgt.window),wgt.vbox); gtk_container_add(GTK_CONTAINER(wgt.vbox),hbox); gtk_widget_show_all(wgt.window); g_signal_connect(GTK_OBJECT(button1),"clicked",GTK_SIGNAL_FUNC(send_file),NULL); g_signal_connect(GTK_OBJECT(button2),"clicked",GTK_SIGNAL_FUNC(file_compress),NULL); g_signal_connect(GTK_OBJECT(button3),"clicked",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window); g_signal_connect(GTK_OBJECT(wgt.window),"delete_event",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window);}//文件压缩窗口void file_compress(GtkWidget *widget,gpointer data){ GtkWidget *hbox, *vbox1, *vbox2, *button; struct widget *pdata; GdkColor color1; int status; pthread_t thid; gdk_color_parse("red",&color1); pdata = g_malloc(sizeof(struct widget)); pdata->window1 = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(pdata->window1),GTK_WIN_POS_CENTER); gtk_window_set_title(GTK_WINDOW(pdata->window1),"Process bar"); gtk_window_set_default_size(GTK_WINDOW(pdata->window1),300,100); hbox = gtk_hbox_new(FALSE,0); vbox1 = gtk_vbox_new(FALSE,0); vbox2 = gtk_vbox_new(FALSE,0); pdata->pbar = gtk_progress_bar_new(); button = gtk_button_new_with_label("取消"); gtk_widget_set_size_request(button,55,30); gtk_widget_set_size_request(pdata->pbar,240,30); gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1); gtk_box_pack_start(GTK_BOX(vbox1),pdata->pbar,FALSE,FALSE,50); gtk_box_pack_end(GTK_BOX(vbox2),button,FALSE,FALSE,50); gtk_box_pack_start(GTK_BOX(hbox),vbox1,FALSE,FALSE,0); gtk_box_pack_end(GTK_BOX(hbox),vbox2,FALSE,FALSE,5); gtk_container_add(GTK_CONTAINER(pdata->window1),hbox); pthread_create(&thid, NULL, compress, NULL); pdata->timer = g_timeout_add(120,progress_timeout,pdata); //printf("\n----->%d",pdata->timer); //pthread_join(thid, (void *)&status); g_signal_connect(pdata->window1,"destroy",G_CALLBACK(destroy_progress),(void *)pdata); g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(destroy_progress),(void *)pdata); gtk_widget_show_all(pdata->window1);}//压缩完成,打印压缩信息void complete_compress(){ GtkWidget *vbox, *vbox1, *hbox, *label, *button; GdkColor color1, color2; gdk_color_parse("LawnGreen",&color1); gdk_color_parse("DarkBlue",&color2); wgt.window2 = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(wgt.window2),GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(wgt.window2),300,150); char buf[MAXLEN]; vbox = gtk_vbox_new(FALSE,0); vbox1 = gtk_vbox_new(FALSE,0); hbox = gtk_hbox_new(FALSE,0); button = gtk_button_new_with_label("确定"); gtk_widget_set_size_request(button,100,30); bzero(buf,sizeof(buf)); sprintf(buf,"源文件大小: %ld Byte\n压缩后文件大小: %ld Byte\n压缩用时: %.2lf seconds\n压缩率: %.2f %%\n",FileLength,sumlength,duration,rate*100); label = gtk_label_new(buf); gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color2); gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1); gtk_box_pack_start(GTK_BOX(vbox1),label,FALSE,FALSE,0); gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,150); gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE,0); gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,15); gtk_container_add(GTK_CONTAINER(wgt.window2),vbox); g_signal_connect(wgt.window2,"destroy",G_CALLBACK(gtk_dialog_destroy),(void *)wgt.window2); g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(gtk_dialog_destroy),(void *)wgt.window2); gtk_widget_show_all(wgt.window2);}//选择解压文件函数void choose_file2(GtkWidget *widget,gpointer data){ GtkWidget *scroll_box; GtkWidget *hbox; GtkWidget *button1; GtkWidget *button2; GtkWidget *button3; GtkWidget *tmp; GtkWidget *label; GdkColor color1; GdkColor color2; GdkColor color3; GdkColor color4; gdk_color_parse("DarkBlue",&color1); gdk_color_parse("LawnGreen",&color2); gdk_color_parse("gray",&color3); gdk_color_parse("red",&color4); tmp = (GtkWidget *)data; gtk_widget_hide(tmp); wgt.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(wgt.window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(wgt.window), 400, 150); gtk_container_set_border_width(GTK_CONTAINER(wgt.window),10); gtk_window_set_title(GTK_WINDOW(wgt.window),"文件解压"); gtk_window_set_resizable(GTK_WINDOW(wgt.window),TRUE); wgt.vbox = gtk_vbox_new(FALSE,20); hbox = gtk_hbox_new(FALSE,20); scroll_box = gtk_scrolled_window_new(NULL,NULL); wgt.text1 = gtk_text_view_new(); gtk_widget_modify_base(wgt.text1, GTK_STATE_NORMAL, &color3); gtk_widget_modify_text(wgt.text1, GTK_STATE_NORMAL, &color1); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_box), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(scroll_box), wgt.text1); gtk_widget_set_size_request(scroll_box,390,50); button1 = gtk_button_new_with_label("选择文件"); button2 = gtk_button_new_with_label("确认解压"); button3 = gtk_button_new_with_label("取消解压"); label = gtk_label_new("待解压文件位置"); gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color1); gtk_widget_modify_fg(GTK_BIN(button1)->child,GTK_STATE_PRELIGHT,&color1); gtk_widget_modify_fg(GTK_BIN(button2)->child,GTK_STATE_PRELIGHT,&color2); gtk_widget_modify_fg(GTK_BIN(button3)->child,GTK_STATE_PRELIGHT,&color4); //gtk_widget_modify_bg(button1, GTK_STATE_PRELIGHT, &color1); //gtk_widget_modify_bg(button2, GTK_STATE_PRELIGHT, &color2); //gtk_widget_modify_bg(button3, GTK_STATE_PRELIGHT, &color3); gtk_box_pack_start(GTK_BOX(wgt.vbox),button1,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(wgt.vbox),label,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(wgt.vbox),scroll_box,FALSE,FALSE,10); gtk_box_pack_start(GTK_BOX(hbox),button2,FALSE,FALSE,10); gtk_box_pack_end(GTK_BOX(hbox),button3,FALSE,FALSE,10); gtk_container_add(GTK_CONTAINER(wgt.window),wgt.vbox); gtk_container_add(GTK_CONTAINER(wgt.vbox),hbox); gtk_widget_show_all(wgt.window); g_signal_connect(GTK_OBJECT(button1),"clicked",GTK_SIGNAL_FUNC(send_file),NULL); g_signal_connect(GTK_OBJECT(button2),"clicked",GTK_SIGNAL_FUNC(file_decompress),NULL); g_signal_connect(GTK_OBJECT(button3),"clicked",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window); g_signal_connect(GTK_OBJECT(wgt.window),"delete_event",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window);}//文件解压窗口void file_decompress(GtkWidget *widget,gpointer data){ GtkWidget *hbox, *vbox1, *vbox2, *pbar, *button; struct widget *pdata; GdkColor color1; pthread_t thid; gdk_color_parse("red",&color1); pdata = g_malloc(sizeof(struct widget)); pdata->window1 = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(pdata->window1),GTK_WIN_POS_CENTER); gtk_window_set_title(GTK_WINDOW(pdata->window1),"Process bar"); gtk_window_set_default_size(GTK_WINDOW(pdata->window1),300,100); hbox = gtk_hbox_new(FALSE,0); vbox1 = gtk_vbox_new(FALSE,0); vbox2 = gtk_vbox_new(FALSE,0); pdata->pbar = gtk_progress_bar_new(); button = gtk_button_new_with_label("取消"); gtk_widget_set_size_request(button,55,30); gtk_widget_set_size_request(pdata->pbar,240,30); gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1); gtk_box_pack_start(GTK_BOX(vbox1),pdata->pbar,FALSE,FALSE,50); gtk_box_pack_end(GTK_BOX(vbox2),button,FALSE,FALSE,50); gtk_box_pack_start(GTK_BOX(hbox),vbox1,FALSE,FALSE,0); gtk_box_pack_end(GTK_BOX(hbox),vbox2,FALSE,FALSE,5); gtk_container_add(GTK_CONTAINER(pdata->window1),hbox); pthread_create(&thid, NULL, decompress, NULL); pdata->timer = g_timeout_add(120,progress_timeout,pdata); g_signal_connect(pdata->window1,"destroy",G_CALLBACK(destroy_progress),(void *)pdata); g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(destroy_progress),(void *)pdata); gtk_widget_show_all(pdata->window1);}//解压缩完成,打印解压信息void complete_decompress(){ GtkWidget *window, *vbox, *vbox1, *hbox, *label, *button; GdkColor color1, color2; gdk_color_parse("LawnGreen",&color1); gdk_color_parse("DarkBlue",&color2); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window),250,150); char buf[MAXLEN]; vbox = gtk_vbox_new(FALSE,0); vbox1 = gtk_vbox_new(FALSE,0); hbox = gtk_hbox_new(FALSE,0); button = gtk_button_new_with_label("确定"); gtk_widget_set_size_request(button,100,30); bzero(buf,sizeof(buf)); sprintf(buf,"压缩文件大小: %ld Byte\n解压后文件大小: %ld Byte\n解压用时: %.2lf seconds\n解压速率: %.2f KB/s\n",FileLength1,FileLength,duration,speed); label = gtk_label_new(buf); gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color2); gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1); gtk_box_pack_start(GTK_BOX(vbox1),label,FALSE,FALSE,0); gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,150); gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE,0); gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,15); gtk_container_add(GTK_CONTAINER(window),vbox); g_signal_connect(window,"destroy",G_CALLBACK(gtk_dialog_destroy),(void *)window); g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(gtk_dialog_destroy),(void *)window); gtk_widget_show_all(window);}void file_ok_sel(GtkWidget *w, GtkFileSelection *fs){ GtkTextIter start, end; const char *buf; //g_print ("%s\n", gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs))); buf = gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)); strcpy(pathname,buf); text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wgt.text1)); gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(text_buffer),&start,&end); gtk_text_buffer_insert(GTK_TEXT_BUFFER(text_buffer),&end,buf,strlen(buf)); gtk_widget_destroy((GtkWidget *)fs);}void send_file(GtkWidget *widget, gpointer data){ GtkWidget *filew; filew = gtk_file_selection_new ("文件选择"); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),"clicked",G_CALLBACK(file_ok_sel), (void *)filew); g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filew)->cancel_button),"clicked",G_CALLBACK (gtk_dialog_destroy), (void *)filew); gtk_widget_show (filew); g_signal_connect (G_OBJECT (filew), "destroy",G_CALLBACK (gtk_dialog_destroy), (void *)filew);}//主函数int main(int argc,char *argv[]){ gtk_init(&argc,&argv); //调用压缩器 compressor(); gtk_main(); return 0;}
运行步骤:
1.安装gtk+2.0环境 Debian: sudo apt-get install libgtk2.0-dev RedHat: sudo yum install gtk2-devel-docs2.编译 gcc -o compressor compressor.c -g -lpthread `pkg-config --cflags --libs gtk+-2.0`3.运行 ./compressor
程序运行部分截图
1 0
- GTK+和C语言实现的哈夫曼文件压缩工具
- C语言+GTK编写的访问数据库
- 计算PE文件校验和的C语言实现
- C语言实现Bmp文件的读入和剪裁
- C语言基于GTK+Libvlc实现的简易视频播放器
- C语言基于GTK+Libvlc实现的简易视频播放器(二)
- 用anjuta编译gtk程序时出现类似与"main.c::10:21:gtk/gtk.h:没有那个文件和目录"问题的解决
- 【C语言】C语言实现文件内容的复制
- 【C语言】C语言实现文件内容的复制
- 文件压缩工具
- 跨盘符文件移动的实现(C语言)
- C语言实现的文件拷贝
- C语言实现文件、文件夹的操作
- 文件复制的C语言实现
- 修改文件后缀的C语言实现
- 基于C语言的内存文件实现
- 文件版通讯录的c语言实现
- C# ZIP压缩工具小程序实现 支持多个文件和文件夹
- Scala学习整理[第四-六章 使用Scala运行类/对象]<Programming In Scala>
- 目前在学coreText绘制,为什么绘制的区域的背景色是黑色,怎么设置背景色?
- dwz框架解读
- view的刷新机制
- Android IPC机制(二)用Messenger进行进程间通信
- GTK+和C语言实现的哈夫曼文件压缩工具
- jQuery性能优化的28个建议
- Mac开发中,请问如何编码实现操作finder打开指定目录,谢谢!
- Spark SQL 之 DataFrame
- BZOJ2091: [Poi2010]The Minima Game
- 怎样在xcode中改变文件夹的颜色
- 自由运动的小球
- 【leetcode】94. Binary Tree Inorder Traversal【java】
- iOS 支付宝快捷支付 请求参数错误