GTK+和C语言实现的哈夫曼文件压缩工具

来源:互联网 发布:云计算 搭建 openstack 编辑:程序博客网 时间:2024/05/17 01:54
/*************************************************************************    > File Name: compressor.c    > Author: hepan    > Mail: hepan@xiyoulinux.org    > Created Time: 20161223日 星期五 111500秒 ************************************************************************/#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的前801代码表示的字符存入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
原创粉丝点击