【问题标题】:Unzipping a file from InputStream and returning another InputStream从 InputStream 解压缩文件并返回另一个 InputStream
【发布时间】:2010-01-14 09:05:06
【问题描述】:

我正在尝试编写一个函数,该函数将接受带有压缩文件数据的InputStream,并返回另一个带有解压缩数据的InputStream

压缩后的文件将只包含一个文件,因此不需要创建目录等...

我尝试查看 ZipInputStream 和其他人,但我对 Java 中如此多不同类型的流感到困惑。

【问题讨论】:

  • 你已经尝试了什么?请添加一些代码示例。

标签: java zip stream


【解决方案1】:

概念

GZIPInputStream 用于压缩为 gzip(“.gz”扩展名)的流(或文件)。它没有任何标题信息。

该类实现了一个流过滤器,用于读取 GZIP 文件格式的压缩数据

如果你有一个真正的 zip 文件,你必须使用 ZipFile 打开文件,询问文件列表(在你的例子中是一个)并询问解压缩的输入流。

如果您有文件,您的方法将类似于:

// ITS PSEUDOCODE!!

private InputStream extractOnlyFile(String path) {
   ZipFile zf = new ZipFile(path);
   Enumeration e = zf.entries();
   ZipEntry entry = (ZipEntry) e.nextElement(); // your only file
   return zf.getInputStream(entry);
}

读取带有 .zip 文件内容的 InputStream

好的,如果你有一个 InputStream,你可以使用(正如@cletus 所说)ZipInputStream。它读取包含标头数据的流。

ZipInputStream 用于带有 [header information + zippeddata] 的流

重要提示:如果您的 PC 中有文件,您可以使用 ZipFile 类随机访问它

这是通过 InputStream 读取 zip 文件的示例:

import java.io.FileInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


public class Main {
    public static void main(String[] args) throws Exception
    {
        FileInputStream fis = new FileInputStream("c:/inas400.zip");

        // this is where you start, with an InputStream containing the bytes from the zip file
        ZipInputStream zis = new ZipInputStream(fis);
        ZipEntry entry;
            // while there are entries I process them
        while ((entry = zis.getNextEntry()) != null)
        {
            System.out.println("entry: " + entry.getName() + ", " + entry.getSize());
                    // consume all the data from this entry
            while (zis.available() > 0)
                zis.read();
                    // I could close the entry, but getNextEntry does it automatically
                    // zis.closeEntry()
        }
    }
}

【讨论】:

  • 我更正了代码,ZipInputStream 必须包装原始输入流:)。谢谢!
  • Helios:zipinput.getNextEntry() 将返回一个 ZipEntry 对象。如何将其转换为流?
  • zipinputstream 表示文件解压后数据的输入流。这就是我返回“zipinput”的原因。但它必须读取当前压缩数据开头的标题和位置才能启动。这就是为什么我首先调用“getnextentry”。让 zipinputstream 读取该标头并准备解压缩其条目(当然,要知道压缩文件名:)。
  • Helios:感谢您迄今为止的意见。我有一个问题,当你只做一个zis.read() 时,数据去哪儿了?我的 zip 文件将只包含一个文件,我只想返回一个未压缩的文件数据流。
  • 哦,好的。 zis.read() (与任何 InputStream.read 一样)返回(并向前移动)一个字节。其他读取函数的工作方式与一次读取更多字节的方式相同。在您的情况下,您只需:1)获取第一个条目(它是......不要使用while循环)2)返回非常“zis”对象:因为它是您需要的未压缩输入流。适合您的代码是第二个块(第一个 EDIT)
【解决方案2】:

如果您可以更改输入数据,我建议您使用GZIPInputStream

GZipInputStreamZipInputStream 不同,因为其中只有一个数据。所以整个输入流代表整个文件。在ZipInputStream 中,整个流还包含其中文件的结构,可以有很多。

【讨论】:

  • 该文件不在我的控制范围内。这是我从服务器下载的文件。以前是先保存到磁盘然后解压,现在想在内存中解压。
  • 重要的不是字节是来自网络套接字还是来自文件。需要区分的是 zip 存档和压缩数据块。如果您编写和读取数据,也许您不会真正关心带有元数据的存档,那么 GZipStream 将是您的选择。您显然正在接收存档(或者将其保存到文件并解压缩它可能会失败,至少如果您通过运行“标准”解压缩程序解压缩)。您确实可以使用 ZipInputStream 将其解压缩到内存中。
【解决方案3】:

它是 scala 语法:

def unzipByteArray(input: Array[Byte]): String = {
    val zipInputStream = new ZipInputStream(new ByteArrayInputStream(input))
    val entry = zipInputStream.getNextEntry
    IOUtils.toString(zipInputStream, StandardCharsets.UTF_8)
}

【讨论】:

  • 这个scala代码有助于解压java.io.InputStream,但它没有使用定义的'entry'来获取下一个文件,也没有最后的close方法?
  • @puligun 是的。你是对的,这只是问题的答案。当然,我们必须稍后关闭流。换句话说,它是一种可以在需要的情况下使用的方法。
【解决方案4】:

除非我遗漏了什么,否则您绝对应该尝试让ZipInputStream 工作,而且没有理由不应该这样做(我当然曾多次使用它)。

你应该做的是尝试让ZipInputStream 工作,如果你不能,发布代码,我们会帮助你解决你遇到的任何问题。

不过,无论您做什么,都不要尝试重新发明它的功能。

【讨论】:

  • 公平地说,java.util.zip 是一个非常令人不快的 API
  • @skaffman 是的,你会认为他们有 ZipFile.unzip(destDir) 方法,对吧?或者一种通过名称/模式轻松查找条目的方法。这个 API 太恶心了。
猜你喜欢
  • 2013-07-29
  • 2016-12-19
  • 2015-11-12
  • 1970-01-01
  • 2012-06-17
  • 2014-04-11
  • 1970-01-01
  • 1970-01-01
  • 2022-11-12
相关资源
最近更新 更多