压缩_压缩编码 - CSDN
  • .tar.gz 格式解压为tar-zxvfxx.tar.gz .tar.bz2格式解压为tar-jxvfxx.tar.bz2

    前言

    Linux常用命令中,有很多用于对文件的压缩或解压,本文将介绍这些解压缩命令中不常见却非常实用的用法。

    tar

    tar是linux中最常用的解压缩命令。tar命令可用于处理后缀名为tar,tar.gz,tgz,.tar.Z,tar.bz2的文件。
    涉及参数说明:

    -c 建立新的压缩文件
    -r 添加文件到已经压缩的文件
    -u 添加改变了和现有的文件到已经存在的压缩文件
    -x 从压缩的文件中提取文件
    -t 显示压缩文件的内容
    -z 支持gzip解压文件
    -j 支持bzip2解压文件
    -v 显示操作过程
    -k 保留源有文件不覆盖
    -C 切换到指定目录
    -f 指定压缩文件
    
    --delete            删除包中文件
    --strip-components  去除目录
    --add-file          向包中添加文件
    

    压缩

    归档tar包,不压缩

    tar -cvf test.tar test1.log test2.log #归档多个文件
    tar -cvf test.tar test/*  #归档test目录下所有文件
    tar -cvf test.tar *.log  #归档所有以.log结尾的文件 
    

    由于这种方式不会进行压缩,仅做了归档,因此速度极快,同时占用空间也较大。

    归档并压缩为tar.gz或tar.bz2

    这种方式打包对文件进行了压缩:

    tar -zcvf test.tar.gz file1 file2 #打包,并以gzip压缩
    tar -jcvf test.tar.bz2 file1 file2 #打包,并以bzip2压缩
    

    查看压缩包中的文件

    如果不想解压,只是想查看压缩包中的文件内容,可以使用-t参数:

    tar -tvf test.tar #可查看test包中有哪些文件
    

    打包后删除源文件

    有时候在打包后可能需要删除源文件,但一个个删除显得麻烦,我们可以使用--remove-files 选项:

    tar -zcvf test.tar.gz test.log --remove-files 
    

    打包除指定目录或文件以外的文件

    对于某些目录下的文件,可能只需要打包部分文件,因此可以使用--exclude选项排除一些不需要打包的文件:

    tar -zcvf test.tar.gz --exclude=test/*.log test/* #打包test目录下所有文件,排除以.log结尾的文件
    

    这里用到了--exclude选项,支持通配符和正则表达式,因此也非常强大。

    向压缩包中更新文件

    例如,压缩包中已经打入了test以及其他文件,现在你只想更新压缩包中的test文件,那么你可以使用--add-file选项:

    tar -tf test.tar --add-file=test #只针对tar包
    

    向tar包中增加文件

    向tar包中增加文件可使用-r参数:

    tar -rf test.tar testfile #在test.tar包中增加文件,只针对tar包
    

    删除压缩包中的文件

    在不解压的情况下,可使用--delete选项删除包中的文件:

    tar --delete -f test.tar  test1 #从test.tar中删除test1文件
    

    解压

    解压tar.gz和tar包到当前目录

    tar -xvf test.tar.gz
    tar -xvf test.tar 
    

    解压到指定目录

    tar -xvf test.tar.gz -C dir
    tar -xvf test.tar -C dir
    

    解压包中指定的文件

    例如test.tar.gz包中文件情况如下:

    1.txt
    log/
    log/1.log
    log/2.log
    log/2.log
    log/4.log
    log/5.log
    

    如果我们只需要解压出log目录下的1.log,只需要执行下面的命令:

    tar -xvf test.tar.gz log/1.log
    tar -xvf test.tar.gz log/1.log -C test #将1.log解压到test目录
    

    解压时去掉目录结构

    压缩包中的文件可能存在多级目录,常规方式解压出来后,对应目录也会存在。如果只想要压缩包的文件,可以去掉目录结构(注意:同一文件夹下文件名不能重):

    tar -xvf test.tar.gz --strip-components=1 #去掉一层目录
    

    解压时不覆盖原文件

    当前目录可能已经存在包中的文件,如果不想解压出来的文件覆盖当前已存在的文件,可使用-k参数(会抛出错误信息):

    tar -xvkf test.tar.gz
    

    特别提醒

    前面所提到的解压或者压缩带的f参数需要放在最后,因为它指定了压缩包名字,否则会出现解压或压缩失败。

    zip/unzip

    zip和unzip命令主要用于处理zip包。

    压缩

    涉及参数说明:

    -d 从压缩文件内删除指定的文件。
    -f 此参数的效果和指定"-u"参数类似,但不仅更新既有文件,如果某些文件原本不存在于压缩文件内,使用本参数会一并将其加入压缩文件中。
    -j 只保存文件名称及其内容,而不存放任何目录名称。
    -r 递归处理,将指定目录下的所有文件和子目录一并处理。
    -u 更换较新的文件到压缩文件内。
    -v 显示指令执行过程或显示版本信息。
    -y 直接保存符号连接,而非该连接所指向的文件,本参数仅在UNIX之类的系统下有效。
    - <压缩效率> 压缩效率是一个介于1-9的数值。
    

    压缩文件

    zip -r test.zip test/ #打包test目录下的文件
    zip -rj test.zip test/ #打包test目录下文件,且压缩包不带test目录
    

    指定压缩率打包文件

    zip -r8 test.zip test/* #数值(1-9)越大,压缩率越高,耗时越长
    

    打包符号链接文件

    前面的命令只能打包普通文件,如果想要打包符号链接文件,则需要使用参数-y:

    zip  -ry test.zip test
    

    向压缩包中增加或更新文件

    有时候需要向压缩包中增加文件,但又不想重新解压打包,可以使用参数-u:

    zip -u test.zip test2 #向test.zip 包中增加test2文件
    

    压缩时加密

    压缩时如果需要对压缩包进行加密,可使用-P参数:

    zip -r test.zip test1 test -P 66666 #使用密码66666加密
    

    删除压缩包的特定文件

    zip -d test.zip test  #删除test.zip包中的test文件
    

    解压

    涉及参数说明:

    -l 显示压缩文件内所包含的文件
    -j 只保存文件名称及其内容,而不存放任何目录名称。
    -o 以压缩文件内拥有最新更改时间的文件为准,将压缩文件的更改时间设成和该
    -v 显示指令执行过程或显示版本信息。
    -d 指定解压目录,目录不存在会创建
    

    查看压缩包中的文件信息

    unzip -l test.zip #可以看到压缩包中的文件名,日期等信息
    unzip -v test.zip #查看更多信息,例如crc校验信息等
    

    解压压缩包

    unzip -o test.zip -d dir #讲test.zip解压到dir目录
    

    解压包中指定的文件

    如果不知道需要解压的文件名,可先查看包中的文件,然后使用下面的方法:

    unzip -o test.zip "1.log" -d dir #解压包中的1.log文件到dir目录
    unzip -o tet.zip "*.log" -d dir  #解压包中所有的log文件
    

    解压时去掉目录结构

    压缩包中有多层目录结构,普通解压仍然会保留目录结构,如果只想要压缩包中的文件,可以使用-j参数:

    zip -oj test.zip -d ./temp  
    

    解压jar包

    jar包是java归档包,但同样可用unzip解压查看里面的文件:

    unzip -o java.jar -d dir
    

    gzip

    涉及参数说明:

    -k 保留源文件
    -d 解开压缩文件
    -r 递归处理,将指定目录下的所有文件及子目录一并处理
    -v 显示指令执行过程
    

    tar命令带有-z参数,并且打包成tar.gz文件时,便调用gzip进行了压缩。gzip对文本的压缩率约有60%~70%,压缩包文件常以gz为后缀。使用-k参数保留源文件:

    gzip -k ./* #当前目录下所有文件进行压缩,每个文件一个gz包
    gzip -rkv ./* 递归压缩
    

    解压也很简单:

    gzip -dv test.gz 
    

    bzip2

    tar命令使用-j参数将文件打包为tar.bz2时,便调用了bzip2进行压缩。bzip2压缩或解压后,会将源文件删除。如果需要保留源文件,可使用-k参数:

    bzip2 -zk test  #压缩test文件
    bzip2 -dk test.bz2  #解压
    

    rar/unrar

    rar和unrar命令并非linux发行版自带命令,需要另外安装。常见用法如下:

    rar a test.tar test  #将test文件压缩为test.tar
    rar e test.rar       #解压test.tar
    unrar x test.rar     #解压test.tar
    

    压缩率比较

    压缩率一般来说:

    tar.bz2>tar.gz>zip>tar
    

    压缩率越高,压缩以及解压的时间也就越长。

    总结

    对文件进行压缩能够节省磁盘空间,进行网络传输时,也能节省带宽,但是需要注意的是,空间和时间是需要根据实际应用进行权衡的。解压缩命令较多,为避免在其他平台使用不便,可选择常用命令进行压缩文件。

     

    展开全文
  • 深入解析数据压缩算法

    万次阅读 2018-06-08 06:26:38
    1、为什么要做数据压缩? 数据压缩的主要目的还是减少数据传输或者转移过程中的数据量。2、什么是数据压缩? 是指在不丢失信息的前提下,缩减数据量以减少存储空间,提高传输、存储和处理效率的一种技术方法。或者...

    1、为什么要做数据压缩?

           数据压缩的主要目的还是减少数据传输或者转移过程中的数据量。

    2、什么是数据压缩?

            是指在不丢失信息的前提下,缩减数据量以减少存储空间,提高传输、存储和处理效率的一种技术方法。或者是按照一定的算法对数据进行重新组织,减少数据的冗余和存储的空间。

      3、常见的数据压缩算法

    (1).LZW压缩

            LZW压缩是一种无损压缩,应用于gif图片。适用于数据中存在大量重固子串的情况。

    原理:

           LZW算法中,首先建立一个字符串表,把每一个第一次出现的字符串放入串表中,并用一个数字来表示,这个数字与此字符串在串表中的位置有关,并将这个数字存入压缩文件中,如果这个字符串再次出现时,即可用表示它的数字来代替,并将这个数字存入文件中。压缩完成后将串表丢弃。如"print" 字符串,如果在压缩时用266表示,只要再次出现,均用266表示,并将"print"字符串存入串表中,在图象解码时遇到数字266,即可从串表中查出266所代表的字符串"print",在解压缩时,串表可以根据压缩数据重新生成。

    编码过程:


         编码后输出:41 42 52 41 43 41 44 81 83 82 88 41 80。输入为17个7位ASC字符,总共119位,输出为13个8位编码,总共104位,压缩比为87%。

    解码过程:

         对输出的41 42 52 41 43 41 44 81 83 82 88 41 80进行解码,如下表所示:


    解码后输出:

    ABRACADABRABRABRA

    特殊标记:
           随着新的串(string)不断被发现,标号也会不断地增长,如果原数据过大,生成的标号集(string table)会越来越大,这时候操作这个集合就会产生效率问题。如何避免这个问题呢?Gif在采用lzw算法的做法是当标号集足够大的时候,就不能增大了,干脆从头开始再来,在这个位置要插入一个标号,就是清除标志CLEAR,表示从这里我重新开始构造字典,以前的所有标记作废,开始使用新的标记。
          这时候又有一个问题出现,足够大是多大?这个标号集的大小为比较合适呢?理论上是标号集大小越大,则压缩比率就越高,但开销也越高。 一般根据处理速度和内存空间连个因素来选定。GIF规范规定的是12位,超过12位的表达范围就推倒重来,并且GIF为了提高压缩率,采用的是变长的字长。比如说原始数据是8位,那么一开始,先加上一位再说,开始的字长就成了9位,然后开始加标号,当标号加到512时,也就是超过9为所能表达的最大数据时,也就意味着后面的标号要用10位字长才能表示了,那么从这里开始,后面的字长就是10位了。依此类推,到了2^12也就是4096时,在这里插一个清除标志,从后面开始,从9位再来。

          GIF规定的清除标志CLEAR的数值是原始数据字长表示的最大值加1,如果原始数据字长是8,那么清除标志就是256,如果原始数据字长为4那么就是16。另外GIF还规定了一个结束标志END,它的值是清除标志CLEAR再加1。由于GIF规定的位数有1位(单色图),4位(16色)和8位(256色),而1位的情况下如果只扩展1位,只能表示4种状态,那么加上一个清除标志和结束标志就用完了,所以1位的情况下就必须扩充到3位。其它两种情况初始的字长就为5位和9位。

    代码示例:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <algorithm>
    #include <vector>
    using namespace std;
    long len=0;//原字符串的长度
    long loc=0;//去重之后字符串的长度
    map<string,long> dictionary;
    vector <long> result;
    #define MAX 100;
    void LZWcode(string a,string s)
    {
        //memset(&result,0,sizeof(int));
        string W,K;
        for(long i=0;i<loc;i++)
        {
            string s1;
            s1=s[i];//将单个字符转换为字符串
            dictionary[s1]=i+1;
        }
        W=a[0];
        loc+=1;
        for(int i=0;i<len-1;i++)
        {
            K=a[i+1];
            string firstT=W;
            string secontT=W;
            if(dictionary.count(firstT.append(K))!=0)//map的函数count(n),返回的是map容器中出现n的次数
                W=firstT;
            else
            {
                result.push_back(dictionary[W]);
                dictionary[secontT.append(K)]=loc++;
                W=K;
            }
        }
        if(!W.empty())
            result.push_back(dictionary[W]);
        for(int i=0;i<result.size();i++)
            cout<<result[i];
    }
    
    void LZWdecode(int *s,int n)
    {
        string nS;
        for(int i=0;i<n;i++)
            for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)
                if(it->second==s[i])
                {
                    cout<<it->first<<" ";
                }
        for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)//输出压缩编码的字典表
            cout<<it->first<<" "<<it->second<<endl;
    }
    int main(int argc, char const *argv[])
    {
        cout<<"本程序的解码是根据输入的编码字符进行的解码,并不是全256 的字符"<<endl;
        cout<<"选择序号:"<<endl;
        cout<<"1.压缩编码   2.解码"<<endl;
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            switch(n)
            {
                case 1:
                {
                    char s[100],a[100];
                    cout<<"输入一串字符:"<<endl;
                    cin>>s;
                    len=strlen(s);
                    for(int i=0;i<len;i++)
                        a[i]=s[i];
                    sort(s,s+len);//排序
                    loc=unique(s,s+len)-s;//去重
                    LZWcode(a,s);
                    break;
                }
                case 2:
                {
                    cout<<"输入解码数组的长度:"<<endl;
                    int changdu;
                    cin>>changdu;
                    cout<<"输入解码数串(每个数串以空格隔开):"<<endl;
                    int s[changdu];
                    for(int i=0;i<changdu;i++)
                        cin>>s[i];
                    LZWdecode(s, changdu);
                    break;
                }
                default:
                    cout<<"你的输入不正确,请从重新开始"<<endl;
            }
            if(n==2)
            {
                auto iter=result.begin();   // 每次正确输入结束后对结果进行清零
                while(iter!=result.end())
                    result.erase(iter++);
            }
        }
        return 0;
    }
    

    (2).霍夫曼压缩

          哈夫曼编码是无损压缩当中最好的方法。它使用预先二进制描述来替换每个符号,长度由特殊符号出现的频率决定。常见的符号需要很少的位来表示,而不常见的符号需要很多位来表示。哈夫曼算法在改变任何符号二进制编码引起少量密集表现方面是最佳的。然而,它并不处理符号的顺序和重复或序号的序列。

    原理:

         利用数据出现的次数构造Huffman二叉树,并且出现次数较多的数据在树的上层,出现次数较少的数据在树的下层。于是,我们就可以从根节点到每个数据的路径来进行编码并实现压缩。

    编码过程:

    假设有一个包含100000个字符的数据文件要压缩存储。各字符在该文件中的出现频度如下所示:

           在此,我会给出常规编码的方法和Huffman编码两种方法,这便于我们比较。

           常规编码方法:我们为每个字符赋予一个三位的编码,于是有:


           此时,100000个字符进行编码需要100000 * 3 = 300000位。


           Huffman编码:利用字符出现的频度构造二叉树,构造二叉树的过程也就是编码的过程。

    这种情况下,对100000个字符编码需要:(45 * 1 + (16 + 13 + 12 + 9)*3 + (9 + 5)*4) * 1000 = 224000

     

    孰好孰坏,例子说明了一切!好了,老规矩,下面我还是用上面的例子详细说明一下Huffman编码的过程。

           首先,我们需要统计出各个字符出现的次数,如下:

           接下来,我根据各个字符出现的次数对它们进行排序,如下:

           好了,一切准备工作就绪。

           在上文我提到,huffman编码的过程其实就是构造一颗二叉树的过程,那么我将各个字符看成树中将要构造的各个节点,将字符出现的频度看成权值。Ok,有了这个思想,here we go!

           构造huffman编码二叉树规则:

    从小到大,

    从底向上,

    依次排开,

    逐步构造。

           首先,根据构造规则,我将各个字符看成构造树的节点,即有节点a、b、c、d、e、f。那么,我先将节点f和节点e合并,如下图:

    于是就有:

    经过排序处理得:

     

            接下来,将节点b和节点c也合并,则有:

           于是有:

           经过排序处理得:

           第三步,将节点d和节点fe合并,得:

           于是有:

           继续,这次将节点fed和节点bc合并,得:

           于是有:

           最后,将节点a和节点bcfed合并,有:

           以上步骤就是huffman二叉树的构造过程,完整的树如下:

           二叉树成了,最后就剩下编码了,编码的规则为:01

           于是根据编码规则得到我们最终想要的结果:

           从上图中我们得到各个字符编码后的编码位:


    代码示例:

    哈夫曼树结构:

    struct element
    {
        int weight;        // 权值域
        int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    };

    weight保存结点权值;lchild保存该节点的左孩子在数组中的下标;rchild保存该节点的右孩子在数组中的下标;parent保存该节点的双亲孩子在数组中的下标。

    哈夫曼算法的C++实现:

    #include<iostream>
    #include <iomanip>
    
    using namespace std;
    // 哈夫曼树的结点结构
    struct element
    {
        int weight;        // 权值域
        int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    };
    // 选取权值最小的两个结点
    void selectMin(element a[],int n, int &s1, int &s2)
    {
        for (int i = 0; i < n; i++)
        {
            if (a[i].parent == -1)// 初始化s1,s1的双亲为-1
            {
                s1 = i;
                break;
            }
        }
        for (int i = 0; i < n; i++)// s1为权值最小的下标
        {
            if (a[i].parent == -1 && a[s1].weight > a[i].weight)
                s1 = i;
        }
        for (int j = 0; j < n; j++)
        {
            if (a[j].parent == -1&&j!=s1)// 初始化s2,s2的双亲为-1
            {
                s2 = j;
                break;
            }
        }
        for (int j = 0; j < n; j++)// s2为另一个权值最小的结点
        {
            if (a[j].parent == -1 && a[s2].weight > a[j].weight&&j != s1)
                s2 = j;
        }
    }
    // 哈夫曼算法
    // n个叶子结点的权值保存在数组w中
    void HuffmanTree(element huftree[], int w[], int n)
    {
        for (int i = 0; i < 2*n-1; i++)    // 初始化,所有结点均没有双亲和孩子
        {
            huftree[i].parent = -1;
            huftree[i].lchild = -1;
            huftree[i].rchild = -1;
        }
        for (int i = 0; i < n; i++)    // 构造只有根节点的n棵二叉树
        {
            huftree[i].weight = w[i];
        }
        for (int k = n; k < 2 * n - 1; k++) // n-1次合并
        {
            int i1, i2; 
            selectMin(huftree, k, i1, i2); // 查找权值最小的俩个根节点,下标为i1,i2
            // 将i1,i2合并,且i1和i2的双亲为k
            huftree[i1].parent = k;
            huftree[i2].parent = k;
            huftree[k].lchild = i1;
            huftree[k].rchild = i2;
            huftree[k].weight = huftree[i1].weight + huftree[i2].weight;
        }
        
    }
      // 打印哈夫曼树
    void print(element hT[],int n)
    {
        cout << "index weight parent lChild rChild" << endl;
        cout << left;    // 左对齐输出 
        for (int i = 0; i < n; ++i) 
        {
            cout << setw(5) << i << " ";
            cout << setw(6) << hT[i].weight << " ";
            cout << setw(6) << hT[i].parent << " ";
            cout << setw(6) << hT[i].lchild << " ";
            cout << setw(6) << hT[i].rchild << endl;
        }
    }
    int main()
    {
        int x[] = { 5,29,7,8,14,23,3,11 };        // 权值集合
        element *hufftree=new element[2*8-1];    // 动态创建数组
        HuffmanTree(hufftree, x, 8);
        print(hufftree,15);
        system("pause");
        return 0;
    }

    说明:

          parent域值是判断结点是否写入哈夫曼树的唯一条件,parent的初始值为-1,当某结点加入时,parent域的值就设置为双亲结点在数组的下标。构造哈夫曼树时,首先将n个权值的叶子结点存放到数组haftree的前n个分量中,然后不断将两棵子树合并为一棵子树,并将新子树的根节点顺序存放到数组haftree的前n个分量的后面。

    (3).游程编码(RLC)

               游程编码又称“运行长度编码”或“行程编码”,是一种无损压缩编码,JPEG图片压缩就用此方法,很多栅格数据压缩也是采用这种方法。

               栅格数据如图3-1所示:

                                                       

                                                                         3-1 栅格数据

      原理:

             用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的“行程”。行程编码因此而得名),使符号长度少于原始数据的长度。只在各行或者各列数据的代码发生变化时,一次记录该代码及相同代码重复的个数,从而实现数据的压缩。

            常见的游程编码格式包括TGA,Packbits,PCX以及ILBM。
    例如:5555557777733322221111111
    行程编码为:(5,6)(7,5)(3,3)(2,4)(1,7)。可见,行程编码的位数远远少于原始字符串的位数。
    并不是所有的行程编码都远远少于原始字符串的位数,但行程编码也成为了一种压缩工具。
    例如:555555 是6个字符 而(5,6)是5个字符,这也存在压缩量的问题,自然也会出现其他方式的压缩工具。
    在对图像数据进行编码时,沿一定方向排列的具有相同灰度值的像素可看成是连续符号,用字串代替这些连续符号,可大幅度减少数据量。

            游程编码记录方式有两种:①逐行记录每个游程的终点列号:②逐行记录每个游程的长度(像元数)

    第一种方式:

            

          上面的栅格图形可以记为:A,3  B,5  A,1  C,4  A,5

          第二种就记作:A,3  B,2  A,1  C,3   A,1

         行程编码是连续精确的编码,在传输过程中,如果其中一位符号发生错误,即可影响整个编码序列,使行程编码无法还原回原始数据。

    代码示例:

           根据输入的字符串,得到大小写不敏感压缩后的结果(即所有小写字母均视为相应的大写字母)。输入一个字符串,长度大于0,且不超过1000,全部由大写或小写字母组成。输出输出为一行,表示压缩结果,形式为:
    (A,3)(B,4)(C,1)(B,2)

          即每对括号内部分别为字符(都为大写)及重复出现的次数,不含任何空格。

    样例输入:aAABBbBCCCaaaaa

    样例输出:(A,3)(B,4)(C,3)(A,5)

    #include<stdio.h>
    #include<string.h>
    char a[1001];
    int main()
    {
        char t;
        int i;
    gets(a);
    int g=1;
    int k=strlen(a);
    if(a[0]>='a'&&a[0]<='z')
        a[0]-=32;
      t=a[0];
    for(i=1;i<=k;i++)
    {
      if(a[i]>='a'&&a[i]<='z')
      a[i]-=32;
      if(a[i]==t)
          g++;
    if(a[i]!=t)
      {
        printf("(%c,%d)",t,g);
         g=1;
           t=a[i];
      }
    }return 0;
    }

    应用场景:

    (1).区域单色影像图

    (2).红外识别图形

    (3).同色区块的彩色图形

    参阅资料:

    https://blog.csdn.net/u012455213/article/details/45502573

    https://www.cnblogs.com/smile233/p/8184492.html

        说明:部分图源来自网络,感谢作者的分享。

    展开全文
  • Kafka压缩

    万次阅读 2020-04-23 21:49:52
    当然你可以选择在业务代码中对每一条消息做压缩处理,之后再发送到kafka中,之后业务消费端再进行解压处理,这种方式对应消息的压缩效率是非常低。而真正有效的压缩是对一批消息进行压缩而不是单独的为每条消息进行...

    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。

    欢迎跳转到本文的原文链接:https://honeypps.com/mq/kafka-compression/


    在某些情况下,整个应用的瓶颈不在于CPU或者磁盘,而是受网络带宽的影响。当然你可以选择在业务代码中对每一条消息做压缩处理,之后再发送到kafka中,之后业务消费端再进行解压处理,这种方式对应消息的压缩效率是非常低。而真正有效的压缩是对一批消息进行压缩而不是单独的为每条消息进行压缩。

    Kafka(本文是以0.8.2.x的版本做基准的)本身可以支持几种类型的压缩,比如gzip和snappy,更高的版本还支持lz4。默认是none,即不采用任何压缩。开启压缩的方式是在客户端调用的时候设置producer的参数。与压缩有关的参数有:

    名称 默认值 在哪使用 描述
    compression.type none new producer configs(kafka-client) The compression type for all data generated by the producer. The default is none (i.e. no compression). Valid values are none, gzip, or snappy. Compression is of full batches of data, so the efficacy of batching will also impact the compression ratio (more batching means better compression).
    compression.codec none kafka-scala-client This parameter allows you to specify the compression codec for all data generated by this producer. Valid values are “none”, “gzip” and “snappy”.
    compressed.topics null kafka-scala-client This parameter allows you to set whether compression should be turned on for particular topics. If the compression codec is anything other than NoCompressionCodec, enable compression only for specified topics if any. If the list of compressed topics is empty, then enable the specified compression codec for all topics. If the compression codec is NoCompressionCodec, compression is disabled for all topics

    上面表格中提及了kafka-client与kafka-scala-client,这两者之间有什么区别呢?kafka-client是kafka的一个分支,其全部使用java语言来开发kafka的客户端。而kafka-scala-client是使用scala语言开发的客户端,两者之间采用的参数会有所不同,注意区分。

    下面演示两个demo来便于区分两者之间的用法。
    1.kafka-client的使用demo:

            Properties properties = new Properties();
            properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
            properties.put("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer");
            properties.put("bootstrap.servers", brokerList);
            properties.put("compression.type", "gzip");
    
            Producer<String,byte[]> producer = new KafkaProducer<String,byte[]>(properties);
    
            ProducerRecord<String,byte[]> producerRecord = new ProducerRecord<String,byte[]>(topic, "messages".getBytes());
            Future<RecordMetadata> future =  producer.send(producerRecord, new Callback() 
            {
                public void onCompletion(RecordMetadata metadata, Exception exception) {
                    System.out.println(metadata.offset());
                }
            });
    

    2.kafka-scala-client的使用demo:

    Properties props = new Properties();
    props.put("serializer.class", "com.kafka.compression.kafka.MessageEncoder");
    props.put("metadata.broker.list", brokerList);
    props.put("producer.type", "async");
    props.put("compression.codec", "gzip");
    
    kafka.javaapi.producer.Producer<Integer, byte[]> producer = new kafka.javaapi.producer.Producer<Integer,
            byte[]>(new kafka.producer.ProducerConfig(props));
    producer.send(new KeyedMessage<Integer, byte[]>(topic, "messages".getBytes()));
    

    下面我们分别采用5个测试样本来进行测试,包括结构化log日志,xls,docx以及随机字符串这4种类型,分别采用Linux gzip工具(gzip -c *** > ***)、java内置的gzip压缩以及kafka内置的压缩进行测试。(其他的压缩方式可以类推,在此不做赘述。)

    查看kafka压缩之后消息的大小,可以通过查看kafka-log文件的大小,没发生一次消息,将前后的文件大小相差即为消息的大小。只需check ****.log文件即可。

    得到测试接入如下表所示:

    Item 1.log 2.log 3.xls 4.docx 随机字符串
    原始文件大小 35136B 51354B 412160B 322737B 204800B
    linux gzip压缩 930B 3557B 90098B 302378B 166474B
    java gzip压缩 924B 3542B 90531B 302687B 166524B
    kafka-client 未压缩 35162B 51380B
    kafka-client 压缩 980B/981B 3607B
    kafka-scala-client sync 未压缩 35162B 51380B
    kafka-scala-client sync 压缩 980B/981B 3606B
    kafka-scala-client async 未压缩 35162B 51380B 412290B 322841B 204852B
    kafka-scala-client async 压缩 980B/981B 3619B 90660B 302803B 166626B
    压缩率 约3% 约7% 约22% 约94% 约81%

    压缩率=文件压缩后的大小与压缩前的大小之比。压缩率一般是越小越好,但是也得越小,一般解压时间也越长。

    通过查看以上测试结果可以发现,kafka的压缩率和linux gzip或者java gzip的压缩率基本相同。

    对于不同的测试样本来说,压缩率会展示出天差地别,不过如果业务方可以先将业务本身的消息采用gzip工具压缩,然后可以估算出开启kafka的压缩率,之后再进行决策。

    你或许会注意到上表中的kafka压缩之后的消息大小会比其他的压缩方式压缩之后的消息会大一点点,这是因为kafka的日志存储结构造成的,kafka将消息存盘并不只是存储消息本身,而是包含了以下结构:

    字段 占用空间大小
    offset 8B
    message size 4B
    crc32 4B
    magic 1B
    attributes 1B
    key length 4B
    key kB
    payload length 4B
    payload nB

    对于一个没有key的消息来说,其占用的存储空间比消息体本身多占用=8B+4B+4B+1B+1B+4B+0B+4B=26B的大小。

    上面的测试都是单条发送整个测试样本的数据的,如果同时发送多条消息,那么会有什么变化呢?我们知道kafka的发送方式有同步和异步之分,异步的发送方式可以批量发送消息,那么会不会批量压缩消息进而使得消息得到更有效的压缩呢?

    我们采用前面的样本1.log进行测试,读取样本中的内容,然后拆分成1KB一条消息进行发送。由于kafka-client没有producer.type的设置,我们这里采用kafka-scala-client进行测试,分为同步和异步:

    Item sync async
    未压缩 36046B 36046B
    压缩 7008B 1578B

    由上表数据可知:如果采用async的发送方式,那么消息会批量发送,在存储上会比sync的方式更节省磁盘空间

    在同步的发送方式中,kafka-logs中消息存储为:
    offset:1 position:0
    offset:2 position:xxx

    一共分成35(25136B/1024B)条消息存储。
    而异步的发送方式中,消息的存储为:
    offset:34 posiotion:0
    一共分成1条消息存储。
    所以可以理解为何async的发送方式比sync的发送方式所呈现的压缩效率更好。

    查看log日志的内容: bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/[topicName]-0/00000000000000000000.log --print-data-log

    附:Java内置的gzip压缩代码:

    package com.kafka.compression.gzip;
    
    import java.io.*;
    import java.util.zip.GZIPInputStream;
    import java.util.zip.GZIPOutputStream;
    
    /**
     * Created by hidden on 2017/6/5.
     */
    public class GzipUtil {
    
        public static void compress(String inFileName, String outFileName) {
            try {
                System.out.println("Createing the Gzip output Stream.");
                GZIPOutputStream out = null;
                try {
                    out = new GZIPOutputStream(new FileOutputStream(outFileName));
                } catch (IOException e) {
                    System.out.println("Could not create file: " + outFileName);
                    e.printStackTrace();
                }
    
                System.out.println("Opening the input file.");
                FileInputStream in = null;
                try {
                    in = new FileInputStream(inFileName);
                } catch (FileNotFoundException e) {
                    System.out.println("File not found: "+inFileName);
                    e.printStackTrace();
                }
    
                System.out.println("Transfering bytes from input file to Gzip format");
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                in.close();
                System.out.println("Completing the Gzip file");
                out.finish();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void uncompress(String inFileName, String outFileName){
            try {
                System.out.println("Opening the compressed file.");
                GZIPInputStream in = null;
                try {
                    in = new GZIPInputStream(new FileInputStream(inFileName));
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                System.out.println("Open the output file.");
                FileOutputStream out = null;
                try {
                    out = new FileOutputStream(outFileName);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
    
    
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                out.flush();
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    欢迎跳转到本文的原文链接:https://honeypps.com/mq/kafka-compression/


    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    展开全文
  • (十九)7-Zip 压缩

    2019-07-15 15:53:44
    版权声明:本文为博主原创文章,未经博主允许不得转载。 本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

    版权声明:本文为博主原创文章,未经博主允许不得转载。
    本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

    一、概述

    1.7z

    一种文件压缩格式,具有高压缩比率,进行数据压缩有多种压缩算法可以选择。与其它压缩格式相比,得到的压缩文档较小,即压缩率最高,节省磁盘空间。

    2.7-Zip

    对 7z 的压缩格式,我们可以使用 7-Zip,下载地址

    完全免费而且开源的压缩软件,相比其他软件有更高的压缩比但同时耗费的资源也相对更多。支持压缩/ 解压缩:7z, XZ, BZIP2, GZIP, TAR, ZIP, WIM。

    3.数据

    压缩率:
    在这里插入图片描述

    压缩文件尺寸:
    在这里插入图片描述
    压缩得分:
    在这里插入图片描述
    压缩时间:
    在这里插入图片描述
    整体来说,7-Zip 的性能相对较好。

    二、7zip 的使用

    1.压缩等级

    0	不压缩
    1	快速压缩
    5	正常压缩
    7	最大压缩
    9	极限压缩
    

    2.压缩命令

    7z a   [输出文件] [待压缩文件/目录] -mx=9 
    

    在这里插入图片描述

    -t7z 	压缩文件的格式为7z(压缩zip则为-tzip)
    -mx=9	设置压缩等级为极限压缩
    

    3.解压命令

    7z x [压缩文件]  -o[输出目录]
    

    在这里插入图片描述

    三、命令行使用 7z

    1.下载源码

    要在安卓中进行使用,我们需要先下载 7zip 的源码。下载地址
    在这里插入图片描述

    也可以使用命令行进行下载:

    wget  https://jaist.dl.sourceforge.net/project/p7zip/p7zip/16.02/p7zip_16.02_src_all.tar.bz2
    

    下载下来的是一个压缩包,进行解压查看。

    2.选取格式

    Runtime.getRuntime().exec(“xxx”)
    

    7z 的使用不需要对执行过程进行干预,也就是不需要在执行过程中操作数据,只在乎最后得到一个 7z 文件或者解压出 7z 文件。因此可以使用命令行来使用 7zip 压缩与解压。(同理对于视频文件的压缩、转换也可以使用ffmpeg 命令行,但是对于实时编码摄像头数据就必须编码完成)

    首先,我们需要在安卓手机中拥有 7zip 的可执行文件,类似 window 中的 7zip.exe。

    进入刚才下载压缩包下的目录, ./CPP/ANDROID/7zr
    在这里插入图片描述

    7z	 使用了插件,能进行更多的格式支持(能支持 tar、zip 等)
    7za	 只是用7zip
    7zr  只支持7z格式
    

    我们只需要 7z 的格式,所以这边我们采用的是 7zr,这是最精简的。(如果要使用 7za 的话也是可以,编译步骤一样)

    3.编译

    我们进入 7zr 目录,查看目录结构。
    在这里插入图片描述
    里面有个 makefile 文件,这个是在 eclipse 创建安卓项目时候使用,我们打开 makefile 文件进行查看,里面就有编译步骤。
    在这里插入图片描述
    进到 jni 目录进行查看,是两个 .mk 文件。
    在这里插入图片描述

    查看 Application.mk 文件。里面就是指定对应的平台,默认只有 armeabi,我们可以在这里进行对对应平台的添加。

    # The ARMv7 is significanly faster due to the use of the hardware FPU
    APP_ABI := armeabi
    # p7zip armeabi and armeabi-v7a run at the same speed (p7zip does not use FPU)
    # APP_ABI := armeabi armeabi-v7a
    #APP_PLATFORM := android-8
    

    修改为:

    # The ARMv7 is significanly faster due to the use of the hardware FPU
    APP_ABI := armeabi-v7a x86
    # p7zip armeabi and armeabi-v7a run at the same speed (p7zip does not use FPU)
    # APP_ABI := armeabi armeabi-v7a
    #APP_PLATFORM := android-8
    
    

    在 jni 目录下按 makefile 文件中写的,运行 ndk-build 。
    在这里插入图片描述
    注: NDK 的版本要使用旧的版本,否者会报错。这边个人是使用 ndk 12 进行编译,下载地址。(ndk 15 太新,编译出错,ndk 10 编译过得去,在项目运行时候 cmake 报错)

    编译成功后的目录:
    在这里插入图片描述

    4.使用

    先把生成的可执行文件拷贝到 assets 目录下,打包进 apk。
    在这里插入图片描述
    运行 7zip 前,先把可执行文件拷贝到安卓系统中。

    	/**
    	 * 把 7z 拷贝到手机
    	 * @param view
    	 */
    	public void load(View view) {
    
    		File diskFilename = new File(getFilesDir(), "7zr");
    
    		//不存在,则进行拷贝
    		if (!diskFilename.exists()) {
    			String assetFilename;
    			//根据cpu 拷贝不同的可执行文件
    			if (Build.CPU_ABI.startsWith("armeabi") ||
    					Build.CPU_ABI.equals("x86")) {
    				assetFilename = "libs/" + Build.CPU_ABI + "/7zr";
    			} else {
    				Toast.makeText(this, "加载错误,平台不符", Toast.LENGTH_SHORT).show();
    				return;
    			}
    			AssetsFileUtil.copyFromAssets(this, assetFilename, diskFilename.getAbsolutePath());
    		}
    
    		//存在但不能执行
    		if (!diskFilename.canExecute()) {
    			//设置可执行并
    			diskFilename.setExecutable(true);
    		}
    
    		Toast.makeText(this, "加载7zr 结果:"
    				+ (diskFilename.exists() && diskFilename.canExecute()),
    				Toast.LENGTH_SHORT).show();
    	}
    

    然后使用代码进行 7zip 压缩和解压命令的执行。具体 demo 见末尾。

    **注:**这边是对 sdcard 目录下的 7-Zip 文件夹进行压缩,所以在运行前需保证改文件夹存在。

    四、NDK 使用 7z

    1.设置编译动态库

    在上面的配置基础上,配置编译成动态库。

    修改 Android.mk 文件末尾,去除配置 pie,使用默认的。设置编译内容为动态库。

    Android.mk

    # Needed since ANDROID 5, these programs run on android-16 (Android 4.1+)
    # pie 是给可执行程序使用的 flag
    # LOCAL_CFLAGS += -fPIE
    # LOCAL_LDFLAGS += -fPIE -pie
    
    include $(BUILD_SHARED_LIBRARY)
    # BUILD_EXECUTABLE 可执行文件
    # BUILD_SHARED_LIBRARY 动态库
    # BUILD_STATIC_LIBRARY 静态库
    

    2.编译

    与编译成执行文件一样的操作步骤,进行编译,等待一会,即可在 libs 下面生产对应的动态库。

    3.添加动态库

    新建 cpp/libs 文件夹,然后把生成的动态库拷贝进来。
    在这里插入图片描述
    在 app 下的 build.gradle 中添加 so 包的引用路径。(如果把 so 放在默认 jniLibs 文件夹下则不需要进行添加,也是可以的。)

    android {
        ...
        sourceSets {
            main {
                jniLibs.srcDirs = ['src/main/cpp/libs']
            }
        }
    }
    

    4.配置 NDK 运行的平台

    在 app 的 build.gradle 中进行添加以下配置:

    android {
        compileSdkVersion 28
        defaultConfig {
    		......
            externalNativeBuild {
                cmake {
                    cppFlags ""
                    abiFilters 'armeabi-v7a','x86'
                }
            }
        }
    }
    

    5.配置 CMakeLists

    在 app 的 build.gradle 中添加 CMakeLists 路径。

    android {
    	......
        externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }
    }
    

    在 app 下创建 CMakeLists.txt 文件。
    在这里插入图片描述
    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.4.1)
    
    set(LIB_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp/libs/${ANDROID_ABI})
    add_library(lib7zr SHARED IMPORTED)
    set_target_properties(lib7zr PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/lib7zr.so)
    
    #根据Android.mk引入头文件
    #设置头文件查找目录
    include_directories(src/main/cpp/lib7zr/CPP/7zip/Archive
    src/main/cpp/lib7zr/CPP/7zip/Archive/7z
    src/main/cpp/lib7zr/CPP/7zip/Archive/BZip2
    src/main/cpp/lib7zr/CPP/7zip/Archive/Common
    src/main/cpp/lib7zr/CPP/7zip/Archive/GZip
    src/main/cpp/lib7zr/CPP/7zip/Archive/Cab
    src/main/cpp/lib7zr/CPP/7zip/Archive/Lzma
    src/main/cpp/lib7zr/CPP/7zip/Archive/Tar
    src/main/cpp/lib7zr/CPP/7zip/Archive/Zip
    src/main/cpp/lib7zr/CPP/7zip/Archive/Split
    src/main/cpp/lib7zr/CPP/7zip/Archive/Z
    src/main/cpp/lib7zr/CPP/7zip/Compress
    src/main/cpp/lib7zr/CPP/7zip/Crypto
    src/main/cpp/lib7zr/CPP/7zip/UI/Console
    src/main/cpp/lib7zr/CPP/7zip/UI/Common
    src/main/cpp/lib7zr/CPP/Windows
    src/main/cpp/lib7zr/CPP/Common
    src/main/cpp/lib7zr/CPP/7zip/Common
    src/main/cpp/lib7zr/C
    src/main/cpp/lib7zr/CPP/myWindows
    src/main/cpp/lib7zr/CPP
    src/main/cpp/lib7zr/CPP/include_windows)
    
    add_library(
                 native-lib
                 SHARED
                 src/main/cpp/native-lib.cpp
                 )
    
    target_link_libraries(
                        native-lib
                        lib7zr
                        log )
    

    这个 CMakeLists.txt 编写是模仿 7zip 进行编写的。查看 Android.mk,把引用到的头文件拷贝进来就是了。

    在这里插入图片描述

    上面的 CMakeLists.txt 使用到了一些 7zip 的文件,我们需要把这些文件拷贝到 app/src/main/cpp/lib7zr 下。

    7zip 下文件:
    在这里插入图片描述

    拷贝后文件:
    在这里插入图片描述

    6.编写 C 代码

    在 app/src/main/cpp 下创建 native-lib.cpp 文件,进行 C 代码的编写。

    native-lib:

    #include <jni.h>
    #include <string>
    #include <7zTypes.h>
    //
    #include <android/log.h>
    
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "7zr",__VA_ARGS__);
    
    //c++与c兼容
    // int a(int x) i_ai
    // i_a
    //表示这个函数在别的地方实现
    extern int MY_CDECL main
            (
    #ifndef _WIN32
            int numArgs, char *args[]
    #endif
    );
    
    void strArgs(const char *cmd, int &args, char pString[66][1024]);
    
    extern "C"
    JNIEXPORT jint JNICALL
    Java_com_xiaoyue_project7zip_ZipCode_exec(JNIEnv *env, jclass type, jstring cmd_) {
        const char *cmd = env->GetStringUTFChars(cmd_, 0);
        //7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
        int numArgs;
        char temp[66][1024] = {0};
        //分割字符串 将值填入变量
        strArgs(cmd, numArgs, temp);
        char *args[] = {0};
        for (int i = 0; i < numArgs; ++i) {
            args[i] = temp[i];
            LOGE("%s", args[i]);
        }
        env->ReleaseStringUTFChars(cmd_, cmd);
        return main(numArgs,args);
    }
    
    void strArgs(const char *cmd, int &numArgs, char argv[66][1024]) {
        //获得字符串长度
        int size = strlen(cmd);
        //argv的两个下标
        int a = 0, b = 0;
        //0 = false
        //记录是否进入空格
        //7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
        //7zr\0
        int inspace = 0;
        for (int i = 0; i < size; ++i) {
            char c = cmd[i];
            switch (c) {
                case ' ':
                case '\t':
                    if (inspace) {
                        //字符串结束符号
                        argv[a][b++] = '\0';
                        a++;
                        //加入下一个有效字符前 复原
                        b = 0;
                        inspace = 0;
                    }
                    break;
                default:
                    //如果是字符
                    inspace = 1;
                    argv[a][b++] = c;
                    break;
            }
        }
        //7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
        //如果最末尾不是空格 就不会进入  case ' ': case '\t': 补上最后一个结束符
        //if(inspace){}
        if (cmd[size - 1] != ' ' && cmd[size - 1] != '\t') {
            argv[a][b] = '\0';
            a++;
        }
        numArgs = a;
    }
    

    同时编写一个 java 类 ZipCode 进行加载 native-lib。

    ZipCode:

    public class ZipCode {
        static {
            System.loadLibrary("native-lib");
        }
    
        //7zr a xxx.7z xx
        public native static int exec(String cmd);
    }
    

    7.测试

    在 MainActivity 中进行代码的调用。

    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    
    		File src = new File(Environment.getExternalStorageDirectory(), "7-Zip");
    		File out = new File(Environment.getExternalStorageDirectory(), "7-Zip.7z");
    		File out2 = new File(Environment.getExternalStorageDirectory(), "7-Zip_code");
    		ZipCode.exec("7zr a " + out.getAbsolutePath() + " " + src.getAbsolutePath() + " -mx=9");
    		ZipCode.exec("7zr x " + out.getAbsolutePath() + " -o" + out2.getAbsolutePath());
    	}
    

    注: 这边是对sdcard 目录下的 7-Zip 文件夹进行压缩,所以在运行前需保证改文件夹存在。

    8.运行结果

    在 sdcard 目录下生成 7-Zip.7z 压缩包和 7-Zip_code 解压文件夹。

    五、使用场景

    可以使用 7-Zip 对上传服务的文件进行压缩,减小体积。也可以使用 7-Zip 对 dex 文件进行压缩,减小 apk 的体积。

    六、附

    代码链接

    展开全文
  • 文件的压缩压缩

    千次阅读 2018-09-10 19:12:15
    背景:看到文件压缩gzip,bzip2。脑子一热,想到能不能再次压缩文件?没有百度到,想要的答案,自己费事来try try。 看不懂的知识:https://blog.csdn.net/xuchuangqi/article/details/52939705 gzip 对于要压缩...
  • Quick Benchmark: Gzip vs Bzip2 vs LZMA vs XZ vs LZ4 vs LZO EDIT: Add zstd Contents  [hide]  1 Selected archives2 Test conditions3 The ...3.1 Compressed
  • 几种压缩算法的压缩和速度比较

    千次阅读 2018-10-23 17:08:38
    Quick Benchmark: Gzip vs Bzip2 vs LZMA vs XZ vs LZ4 vs LZO EDIT: Add zstd Contents  [hide]  1 Selected archives 2 Test conditions 3 The file test results 3.1 Compressed file size in ...
  • 压缩的好处和坏处

    千次阅读 2020-05-29 15:33:23
    1. 压缩的好处和坏处 压缩技术分为有损和无损:大数据场景下我们用到的都是无损;不允许丢失数据 好处 减少存储磁盘空间 降低IO(网络的IO和磁盘的IO) 加快数据在磁盘和网络中的传输速度,从而提高系统的...
  • zip压缩工具 tar打包 打包并压缩

    万次阅读 2018-04-19 05:51:55
    1,zip压缩工具。 zip的压缩包在windows和linux中都比较常用,它可以压缩目录和文件,压缩时录时,需要指定目录下的文件。zip后面先跟目标文件名,即压缩后得自定义压缩包名,然后跟要压缩的文件或目录。没有该命令...
  • 1. 压缩格式 .zip .gz .bz2 .tar.gz .tar.bz2 2. zip压缩与解压缩 2.1 压缩 格式 zip 压缩文件名 源文件 选项 -r:压缩目录 2.2 解压缩 unzip 压缩文件 3. gz压缩与解压缩 3.1 压缩 压缩为.gz格式的压缩文件,...
  • 前端代码压缩的方式

    千次阅读 2018-10-29 23:11:21
    1.使用在线网站进行压缩 2.nodejs提供了html-minifier工具 3.后端模板引擎渲染压缩 Css代码压缩 1.使用在线网站进行压缩 2.使用html-minifier对html中的css进行压缩 3.使用clean-css对css进行压缩 Js压缩与...
  • Linux学习笔记--压缩和解压缩命令

    千次阅读 2016-04-13 18:57:49
    .zip格式压缩:zip 压缩文件名 源文件 #压缩文件zip -r 压缩文件名 源目录 #压缩目录.zip格式解压缩:unzip 压缩文件 #解压缩.zip格式文件注意: 1) zip命令可以压缩文件也可以压缩目录。 2) .zip压缩格式在Linux...
  • Linux 下如何压缩/解压缩文件

    千次阅读 2018-08-28 10:08:31
    Linux 下比较常用的压缩文件 为zip类的压缩文件,下面介绍下如何压缩文件。 使用cd命令切换到要压缩文件的目录 使用 zip -q -r 压缩后的文件.zip 文件名 即可压缩。 当然不切换到目录也可以,使用pwd 查看出...
  • 文章目录1 .zip格式压缩与解压缩1.1 .zip格式压缩1.2 .zip格式解压缩2 .gz格式压缩与解压缩2.1 .gz格式压缩2.2 .gz格式解压缩3 .bz2格式压缩与解压缩3.1 .bz2格式压缩3.2 .bz2格式解压缩4 .tar格式压缩与解压缩4.1 ....
  • 测试-各种压缩算法对比

    千次阅读 2019-05-18 23:43:20
  • 16.1 tar:进行归档和压缩 16.2 gzip:压缩或解压缩gzip文件 16.3 gunzip:解压缩gzip文件 16.4 zcmp:比较gzip压缩文件 16.5 zdiff:比较gzip压缩文件 16.6 zforce:在所有的gzip文件上强制添加.gz扩展 16.7 ...
  • 浅谈压缩感知(十三):压缩感知与传统压缩 导言: 压缩感知,顾名思义,就是感知压缩,这里包含两层意思,1、感知,即采集或采样,在传统的信号采集中,为了不失真,必须满足Nyquist采样定理,在上一篇博文已经...
  • Zip的压缩级别

    2020-01-07 10:43:04
    Zip是Linux/Unix压缩和文件打包实用程序,它主要用于压缩文件/目录,而其配套程序(解压缩)用于解压缩zip包,这两个程序都可以使用PKZIP生成的档案,使用最近发布的zip,如果在zip编译期间包含bzip2库,则它支持...
  • 结果是不一样的 ?????
  • Linux常用命令(六)

    2019-10-05 04:37:08
    一、常用压缩格式 1、常用压缩格式: .zip、.rar、.gz、.bz2 2、常用压缩格式:.tar.gz、.tar.bz2 二、.zip格式压缩压缩 1、文件压缩:zip 压缩文件名 压缩文件 2、目录压缩:zip -r 压缩文件名 压缩目录...
1 2 3 4 5 ... 20
收藏数 1,181,283
精华内容 472,513
关键字:

压缩