从远程归档文件中提取单个文件的方法是什么?

12

给定:

  1. 归档文件的URL(例如zip文件)
  2. 归档文件内的完整文件名(包括路径)

我正在寻找一种方法(最好使用Java),可以创建该文件的本地副本,而无需先下载整个归档文件

据我(有限)的了解,这应该是可能的,但我不知道如何做到。我一直在使用TrueZip,因为它似乎支持多种归档类型,但我对其以这种方式工作的能力表示怀疑。有人有类似的经验吗?

编辑:我也希望能够使用tarballs和zipped tarballs完成类似操作。

4个回答

11

至少,您需要下载存档的一部分,包括您想要提取的文件的压缩数据。这表明以下解决方案:打开一个URLConnection到存档,获取其输入流,在其中包装一个ZipInputStream,并重复调用getNextEntry()closeEntry()以遍历文件中的所有条目,直到找到所需的条目。然后,您可以使用ZipInputStream.read(...)读取其数据。

Java代码应该类似于以下内容:

URL url = new URL("http://example.com/path/to/archive");
ZipInputStream zin = new ZipInputStream(url.getInputStream());
ZipEntry ze = zin.getNextEntry();
while (!ze.getName().equals(pathToFile)) {
    zin.closeEntry(); // not sure whether this is necessary
    ze = zin.getNextEntry();
}
byte[] bytes = new byte[ze.getSize()];
zin.read(bytes);

当然,这还没有经过测试。


谢谢,这似乎工作得很好(除了一些小错误),但不幸的是它只能处理zip归档文件。 - Oak
3
是的,你知道为什么它被称为“ZipInputStream”吗?;-) 如果你在互联网上搜索,你可能会找到一个类似使用方式的“TarInputStream”,或者如果没有的话,你可以自己编写一个。这很容易,因为tar文件并没有被压缩,它基本上只是每个文件的头部,后面跟着文件数据。(维基百科有格式的描述) 对于gzip压缩的tar档案,Java标准库有一个“GZIPInputStream”,你可以与tar流一起使用。 - David Z
实际上,Apache 有一个 TarInputStream 类 :) - Oak
1
很棒的解决方案,只需要进行微小的调整,干杯!ZipInputStream zin = new ZipInputStream(url.openStream()); - Fahad Rauf

5
与其他答案不同的是,我想指出ZIP条目是单独压缩的,因此(理论上)您不需要下载除目录和条目本身之外的任何内容。服务器需要支持Range HTTP头才能实现此功能。
标准Java API仅支持从本地文件和输入流读取ZIP文件。据我所知,没有为从随机访问远程文件读取提供支持的规定。
由于您正在使用TrueZip,我建议使用Apache HTTP Client实现de.schlichtherle.io.rof.ReadOnlyFile并创建一个de.schlichtherle.util.zip.ZipFile
对于压缩的TAR档案,这将不会提供任何优势,因为整个档案都一起压缩了(除了使用InputStream并在获取条目后杀死它)。

3

从 TrueZIP 7.2 版本开始,模块 TrueZIP Path 中提供了新的客户端 API。该 API 是 JSE 7 的 NIO.2 FileSystemProvider 的一个实现。使用此 API,您可以按以下方式访问 HTTP URI:

Path path = new TPath(new URI("http://acme.com/download/everything.tar.gz/README.TXT"));
try (InputStream in = Files.newInputStream(path)) {
    // Read archive entry contents here.
    ...
}

1

我不确定是否有一种方法可以在不先下载整个ZIP文件的情况下提取单个文件。但是,如果您是托管ZIP文件的人,您可以创建一个Java servlet,该servlet读取ZIP文件并在响应中返回所请求的文件:

public class GetFileFromZIPServlet extends HttpServlet{
  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException{
    String pathToFile = request.getParameter("pathToFile");

    byte fileBytes[];
    //get the bytes of the file from the ZIP

    //set the appropriate content type, maybe based on the file extension
    response.setContentType("...");

    //write file to the response
    response.getOutputStream().write(fileBytes);
  }
}

很遗憾,我不是托管文件的人...但这是一个好观点。 - Oak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接