如何从远程存档文件中提取单个文件?

时间:2010-06-26 23:33:08

标签: java download extract tar archive

鉴于

  1. 存档的网址(例如zip文件)
  2. 该存档中文件的全名(包括路径)
  3. 我正在寻找一种方法(最好是用Java)来创建该文件的本地副本,而不先下载整个存档

    从我(有限的)理解应该是可能的,虽然我不知道该怎么做。我一直在使用TrueZip,因为它似乎支持各种各样的存档类型,但我对它以这种方式工作的能力存有疑虑。有没有人有这方面的经验?

    编辑:能够用tarball和压缩的tarball做到这一点对我来说也很重要。

4 个答案:

答案 0 :(得分:9)

嗯,至少,你必须下载档案的一部分,包括你想要提取的文件的压缩数据。这表明以下解决方案:打开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);

当然,这是未经测试的。

答案 1 :(得分:5)

与此处的其他答案相反,我想指出ZIP条目是单独压缩的,因此(理论上)您不需要下载除目录和条目本身之外的任何内容。服务器需要支持Range HTTP标头才能生效。

标准Java API仅支持从本地文件和输入流中读取ZIP文件。据我所知,没有从随机访问远程文件中读取的规定。

由于您使用的是TrueZip,我建议您使用Apache HTTP Client实现de.schlichtherle.io.rof.ReadOnlyFile并使用它创建de.schlichtherle.util.zip.ZipFile

这不会为压缩的TAR压缩文件提供任何优势,因为整个存档被压缩在一起(除了使用InputStream并在您输入时将其终止)。

答案 2 :(得分:2)

自TrueZIP 7.2以来,模块TrueZIP Path中有一个新的客户端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.
    ...
}

答案 3 :(得分:0)

我不确定是否有办法从ZIP中提取单个文件而不先下载整个文件。但是,如果你是托管ZIP文件的那个,你可以创建一个Java 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);
  }
}