首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么base64 64编码的数据压缩得如此糟糕?

为什么base64 64编码的数据压缩得如此糟糕?
EN

Stack Overflow用户
提问于 2016-06-30 13:17:40
回答 3查看 56.2K关注 0票数 74

最近,我正在压缩一些文件,我注意到bad 64编码的数据似乎压缩得很糟糕。以下是一个例子:

  • 原始文件:429,7 MiB
  • xz -913,2 MiB / 429,7 MiB = 0,031 4,9 MiB/s 1:28压缩
  • base64 it并通过xz -926,7 MiB / 580,4 MiB = 0,046 2,6 MiB/s 3:47压缩
  • base64原始压缩xz文件: 17,8 MiB在几乎没有时间的情况下=预期的1.33x大小增加

所以可以观察到的是:

  • xz压缩了非常好的☺
  • base64 64编码的数据不能很好地压缩,它比未编码的压缩文件大2倍。
  • base64 64-然后压缩比压缩后的base64 64更糟糕,速度更慢。

这怎么可能呢?Base64是一种无损、可逆的算法,为什么它会对压缩产生如此大的影响?(我也尝试过使用gzip,并有类似的结果)。

我知道这对base64 64-然后压缩一个文件没有意义,但大多数情况下,一个人无法控制输入文件,而且我会认为,由于base64 64编码文件的实际信息密度(或任何名称)将与非编码版本几乎相同,因此可以进行类似的可压缩。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-30 14:56:22

大多数通用压缩算法都使用单字节粒度

让我们考虑以下字符串:

代码语言:javascript
复制
"XXXXYYYYXXXXYYYY"
  • 运行长度编码算法会说:“那是4 'X',后面是4 'Y',后面是4 'X',后面是4‘Y’。”
  • Lempel-Ziv算法会说:“这是字符串'XXXXYYYY',后面跟着同一个字符串:让我们用第一个引用替换第二个字符串。”
  • Huffman编码算法会说:“该字符串中只有2个符号,所以每个符号只能使用一个比特。”

现在,让我们用Base64对字符串进行编码。我们得到的是:

代码语言:javascript
复制
"WFhYWFlZWVlYWFhYWVlZWQ=="

现在所有的算法都在说:“那是什么样的混乱?”他们不太可能很好地压缩那根绳子。

作为提醒,Base64基本上是将(0.255)中的3个字节组重新编码为(0.63)中的4个字节组:

代码语言:javascript
复制
Input bytes    : aaaaaaaa bbbbbbbb cccccccc
6-bit repacking: 00aaaaaa 00aabbbb 00bbbbcc 00cccccc

然后将每个输出字节转换为一个可打印的ASCII字符。按照惯例,这些字符(这里每10个字符有一个标记)如下:

代码语言:javascript
复制
0         1         2         3         4         5         6
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

例如,我们的示例字符串以十六进制中等于0x58的三个字节组开始(字符“X”的ASCII代码)。或者二进制数: 01011000。让我们应用Base64编码:

代码语言:javascript
复制
Input bytes      : 0x58     0x58     0x58
As binary        : 01011000 01011000 01011000
6-bit repacking  : 00010110 00000101 00100001 00011000
As decimal       : 22       5        33       24
Base64 characters: 'W'      'F'      'h'      'Y'
Output bytes     : 0x57     0x46     0x68     0x59

基本上,在原始数据流中明显出现的模式"3倍于字节0x58“在编码数据流中不再明显,因为我们已经将字节分解为6位数据包,并将它们映射到现在看来是随机的新字节。

或者换句话说:我们破坏了大多数压缩算法所依赖的原始字节对齐。

无论采用何种压缩方法,都会严重影响算法的性能。这就是为什么你应该总是先压缩,然后编码。

对于加密来说更是如此:先压缩,再加密。

编辑--关于LZMA的一个注记

正如MSalters注意到的,LZMA -- xz正在使用的LZMA --正在处理比特流而不是字节流。

不过,该算法还将受到Base64编码的影响,这种编码方式与我先前的描述基本一致:

代码语言:javascript
复制
Input bytes      : 0x58     0x58     0x58
As binary        : 01011000 01011000 01011000
(see above for the details of Base64 encoding)
Output bytes     : 0x57     0x46     0x68     0x59
As binary        : 01010111 01000110 01101000 01011001

即使在位级工作,在输入二进制序列中识别模式也比在输出二进制序列中识别模式要容易得多。

票数 167
EN

Stack Overflow用户

发布于 2016-06-30 13:46:40

压缩必然是一种在多位上工作的操作。压缩个人"0“和"1”是不可能的。即使如此,压缩通常一次只能在有限的一组位上工作。xz中的LZMA算法不会同时考虑所有36亿比特。它查看更小的字符串(<273字节)。

现在看看基- 64编码的功能:它用一个4字节的字替换一个3字节(24位)的字,只使用256个可能的值中的64个。这给了你x1.33的增长。

现在非常清楚的是,这种增长必须导致一些子字符串超过编码器的最大子字符串大小。这使得它们不再被压缩为单个子字符串,而是被压缩为两个单独的子字符串。

由于您有大量的压缩(97%),显然您的情况是非常长的输入子串被压缩为一个整体。这意味着,您还将有许多子字符串是基本的-64扩展超过编码器可以处理的最大长度。

票数 11
EN

Stack Overflow用户

发布于 2018-06-04 05:11:49

不是Base64。它的内存要求库“预设7-9类似预设6,但使用更大的字典,并有更高的压缩和解压缩内存要求。”https://tukaani.org/xz/xz-javadoc/org/tukaani/xz/LZMA2Options.html

票数 -7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38124361

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档