当前位置: 首页 > 知识库问答 >
问题:

对于Java中明显的gzip文本,不是gzip格式

禄光霁
2023-03-14

我一直在尝试实现解压以GZIP格式压缩的文本,下面是我实现的方法

private byte[] decompress(String compressed) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ByteArrayInputStream in = new 
        ByteArrayInputStream(compressed.getBytes(StandardCharsets.UTF_8));
    GZIPInputStream ungzip = new GZIPInputStream(in);
    byte[] buffer = new byte[256];
    int n;
    while ((n = ungzip.read(buffer)) >= 0) {
        out.write(buffer, 0, n);
    }
    return out.toByteArray();
}

现在我正在测试以下压缩文本的解决方案

H4sIAAAAAAAACjM0MjYxBQAcOvXLBQAAAA==

而且gzip格式也没有例外。我尝试了不同的方法,但仍然存在这个错误。也许有人知道我做错了什么?

共有1个答案

谈灵均
2023-03-14

这不是gzip格式的。一般来说,压缩后的数据不能是字符串(因为压缩后的数据是字节,而字符串不是字节。一些语言/教程/20世纪80年代的思维将二者混为一谈,但现在是20世纪20年代。我们不再这样做了。这里的字符比英语中使用的要多)。

看起来可能发生了以下情况:

  • 有人有一些数据。
  • 他们把它压缩了。
  • 然后他们使用Base64编码将gzip流(字节)转换为字符。
  • 他们寄给你了
  • 您现在想回到数据。

考虑到发生了两个转换(首先是gzip-it,然后是base64-it),您还需要做两个相反的转换。你需要:

  • 获取输入字符串,并对其进行de-base64处理,得到字节

因此:

byte[] gzipped = java.util.Base64.getDecoder().decode(compressed);
var in = new GZIPInputStream(new ByteArrayInputStream(gzipped));
return in.readAllBytes();

注:

像这样将数据从输入推送到输出流是一种资源浪费和一堆挑剔的代码。没有必要写这个;只需调用readAllBytes

如果传入的Base64很大,有一些方法可以以流式传输的方式来实现这一点。这需要这个方法接收一个Reader(而不是不能流式传输的String),并返回一个InputStream而不是byte[]。当然,如果输入不是特别大,就没有必要了。上面的方法有些浪费——基本64版数据和非基本64版数据,以及解压缩的数据同时都在内存中,你无法避免这一点,垃圾收集器也无法收集这两者之间的任何东西(因为调用方很可能会继续引用基本64版字符串)。

换句话说,如果压缩率为50%,且未压缩数据总量为100MB,则此方法需要的时间超过:

100MB(未压缩)50MB(压缩)50*4/3=67MB(压缩但基于64MB)=~217MB内存。

您比我们更清楚VM运行在多少堆上,以及输入数据可能会有多大。

注意:Base64传输效率极低,每3个字节的输入数据需要4个字节的Base64内容,如果数据传输采用UTF-16,则每3个字节甚至需要8个字节。哎哟考虑到内容是gzip压缩的,这感觉有点愚蠢:首先我们煞费苦心地缩小这个东西的大小,然后我们随意地把它放大33%,可能没有什么好的理由。你可能想检查一下通向这个的“管道”,也许你可以。。。消除这个问题的base64方面。

例如,如果你有一个有线协议,有人认为JSON是个好主意,那么。。仅仅不要这样做。如果需要传输大量原始数据,JSON不是一个好主意。使用protobuf,或者发送JSON和Blob的组合,等等。

 类似资料:
  • 我试图使用以下Java代码来压缩和解压字符串。但是,从一个新的ByteArrayInputStream对象创建一个新的GZipInputStream对象的那一行抛出了一个“java.util.zip.ZipException:Not in GZIP格式”异常。有人知道怎么解决这个问题吗?

  • 我想为我的web应用程序启用GZIP压缩。我在网上搜索了一下,发现了两个不同的选项: 在嵌入式容器中启用压缩,如Spring文档(https://docs.Spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html-latest section)中所述 使用解析器,如以下所述:ht

  • import "compress/gzip" gzip包实现了gzip格式压缩文件的读写,参见RFC 1952。 const ( NoCompression = flate.NoCompression BestSpeed = flate.BestSpeed BestCompression = flate.BestCompression

  • gzip 是 GNU zip 的缩写,它是一个 GNU 自由软件的文件压缩程序,也经常用来表示 gzip 这种文件格式。软件的作者是 Jean-loup Gailly 和 Mark Adler。 gzip 的基础 是DEFLATE,DEFLATE 是 LZ77 与哈夫曼编码的一个组合体。DEFLATE 最初是作为 LZW 以及其它受专利保护的数据压缩算法的替代版本而设计的,当时那些专利限制了 co

  • 问题内容: 我是Go的新手,无法弄清楚如何使用该软件包对我有利。基本上,我只想写一些东西到文件中,将其gzip压缩,然后通过另一个脚本直接从压缩格式读取。如果有人可以给我一个有关如何执行此操作的示例,我将不胜感激。 问题答案: 所有压缩包都实现相同的接口。您将使用以下方式进行压缩: 并解压缩:

  • 问题内容: 对于大数据项目,我计划使用spark,它具有一些不错的功能,例如用于重复工作负载的内存计算。它可以在本地文件或HDFS之上运行。 但是,在官方文档中,我找不到有关如何处理压缩文件的任何提示。实际上,处理.gz文件而不是解压缩文件可能非常有效。 有没有一种方法可以手动实现读取gzip文件,或者在读取.gz文件时已经自动完成解压缩? 问题答案: 从Spark Scala编程指南的“ Had