【问题标题】:Java Zip File ExtractionJava Zip 文件提取
【发布时间】:2017-08-21 05:30:45
【问题描述】:

我有一个 GTFS 计划管理器,它会自动从指定的提供程序 URL 下载一个压缩文件,并将其中的文件即时提取到指定的文件夹。因此,在此过程结束时,该文件夹仅包含提取的文件,而不是压缩文件本身。

到目前为止,这一直有效,但与

http://mta.maryland.gov/_googletransit/latest/google_transit.zip

由于某种原因它不起作用。当我从流中获取第一个 zip 条目时,它为空。但是,我可以手动将压缩文件下载到本地文件夹,将我的 java 应用程序中的 URL 更改为它,然后它就可以正常提取了。只是动态提取不起作用。

通过按原样运行下面的代码来证明这一点:您将看到失败。如果您随后将压缩文件手动下载到“feeds”文件夹,并在提取作品下方的 main 中交换注释的“extractFilesFromFeed.extract”行。

问题是我是否可以在下面进行更改,以便可以即时提取此特定 URL?

===

import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ExtractFilesFromFeed {

  private Logger logger = Logger.getLogger("");

  public void extract(String feedLocation, String feedFolder) throws Exception  {
    if (feedLocation == null || feedLocation.length() == 0) {
      String tmp = "Invalid feed location specified for GTFS schedule file extraction";
      throw new Exception(tmp);
    }
    else if (feedFolder == null || feedFolder.length() == 0) {
      String tmp = "Invalid feed folder specified for GTFS schedule file extraction";
      throw new Exception(tmp);
    }
    else {
      logger.log(Level.INFO, String.format("Extracting GTFS schedule files from %s to %s", 
          feedLocation, feedFolder));
    }

    URL url;
    if (feedLocation.startsWith("http")) {
      url = new URL(feedLocation);
    }
    else {
      url = new File(feedLocation).toURI().toURL();
    }

    File dir = new File(feedFolder);
    if(!dir.exists()){
      dir.mkdir();
    }

    byte[] buffer = new byte[8192];
    ZipInputStream zis = new ZipInputStream(url.openStream());
    ZipEntry ze = zis.getNextEntry();

    if (ze == null) {
      logger.log(Level.WARNING, "Unable to get first entry from zip file, aborting download");
      zis.close();
      throw new Exception(String.format("Unable to get first entry from zip file %s", feedLocation));
    }

    while (ze != null){
      String zipFileName = ze.getName();
      if (ze.isDirectory()) {
        dir = new File(feedFolder + "/" + zipFileName);
        if(!dir.exists()){
          dir.mkdir();
        }
      }
      else {
        FileOutputStream fos = new FileOutputStream(feedFolder + File.separator + zipFileName);
        int len;
        while ((len = zis.read(buffer)) > 0) {
          fos.write(buffer, 0, len);
        }
        fos.close();   
      }
      ze = zis.getNextEntry();
    }
    zis.close();
  }

  public static void main(String[] args) throws Exception {
    ExtractFilesFromFeed extractFilesFromFeed = new ExtractFilesFromFeed();
    extractFilesFromFeed.extract("http://mta.maryland.gov/_googletransit/latest/google_transit.zip", "feeds");
    //extractFilesFromFeed.extract("feeds/google_transit.zip", "feeds");
  }
}

【问题讨论】:

  • 一次调试您的程序并尝试查找错误。 SO 是一个问答网站,不是编码服务,也不是调试帮助 - 您的问题非常广泛“我的代码有什么问题” - 确定问题并编辑您的问题
  • 简而言之,问题是上面的java代码可以提取指定的zip文件,但它不能下载和提取相同的文件,我想知道有没有其他人看到java和压缩文件的这个问题。该代码可以毫无问题地下载和提取其他zip文件。
  • 实际上,这看起来与 HTTP 301 有关 - 请参阅 github.com/CUTR-at-USF/gtfs-realtime-validator/issues/…
  • stackoverflow.com/a/18431514/937715 处的 HTTP 301 重定向解决方案。

标签: java zip


【解决方案1】:

看起来这里实际上有两个问题:

  1. http://mta.maryland.gov/_googletransit/latest/google_transit.zip 有一个 HTTP 301 重定向到 https://mta.maryland.gov/_googletransit/latest/google_transit.zip 的安全 SSL 版本。
  2. SSL 握手可能由于缺少安全策略文件而失败

对于重定向,您需要使用如下内容:

URL url;
if (feedLocation.startsWith("http")) {
    url = new URL(feedLocation);
    URLConnection urlConnection = url.openConnection();
    // Check for HTTP 301 redirect
    String redirect = urlConnection.getHeaderField("Location");
    if (redirect != null) {
        logger.log(Level.WARNING, "Redirecting to " + redirect);
        url = new URL(redirect);
    }
} else {...

然后,当打开输入流时,您可能想要捕获并记录任何SSLHandshakeExceptions

try {
    ZipInputStream zis = new ZipInputStream(url.openStream());
    ...
} catch (SSLHandshakeException sslEx) {
    logger.log(Level.ERROR, "SSL handshake failed.  Try installing the JCE Extension - see http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html");
}

要安装JCE Extension,您需要将JVM /security 目录中的US_export_policy.jarlocal_policy.jar 文件(例如C:\Program Files\Java\jdk1.8.0_73\jre\lib\security)替换为JCE 扩展下载中的JAR 文件。

我刚刚在我们的项目中修复了同样的问题 - 解决该问题的提交是 https://github.com/CUTR-at-USF/gtfs-realtime-validator/commit/180785d22ca58afa2463b322ad4e1b122c5f0a30,该问题的 Github 问题是 https://github.com/CUTR-at-USF/gtfs-realtime-validator/issues/89

感谢 301 Moved Permanently 提供 HTTP 301 重定向解决方案,感谢 https://stackoverflow.com/a/30760134/937715 安装 JCE 扩展。

【讨论】:

  • 这是本例中的分辨率。重定向被视为 zip 文件,因此前 4 个字节不是正确的文件签名,应该是 0x04034b50。在 java 8 ZipInputStream 类中有一个检查。
  • @paulh 很高兴这有效!您能否继续接受它作为答案,以便其他人也知道?
  • 我试过了,但即使它记录了我的操作,它也不会公开显示它,因为我是系统新手并且声誉分数低于 15。
  • 啊,好的。你可以投票吗?或者这也受到限制?
  • 好的,我实际上是在尝试投票以接受答案,这是受到限制的。刚刚注意到点击后颜色变为绿色的刻度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 2014-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多