【问题标题】:Downloading and unzipping file in another thread giving corrupted archive在另一个线程中下载和解压缩文件,导致存档损坏
【发布时间】:2018-01-23 22:04:43
【问题描述】:

我正在尝试从给定的 url 下载 .zip 存档并将其解压缩到选定的位置。由于下载量很大,我尝试在不同的线程中执行它,因此它不会冻结整个事情,但它并没有真正取得完全成功......通常,我会创建一个可运行和线程对象,但现在,由于我使用的是 javafx,它给出了一些错误。我在网上搜索,我不得不改用Platform.runLater()。这是我的代码:

private void startTask(Label st, ListView<String> view, HashMap<String, String> hash)
{

    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            runTask(st,view,hash);
        }
    });
}

private void runTask(Label st, ListView<String> view, HashMap<String, String> hash){
    String link = hash.get(view.getSelectionModel().getSelectedItem());
    File file = new File("temp.zip");
    try {
        FileUtils.copyURLToFile(new URL(link), file);
        byte[] buffer = new byte[1024];
        ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
        ZipEntry zipEntry = zis.getNextEntry();
        File newFile;
        FileOutputStream fos;
        String fileName;
        while(zipEntry != null){

            fileName = zipEntry.getName();
            if(fileName.contains("##TEMP##")) continue;
            if(fileName.contains("MACOSX")) continue;
            newFile = new File(fileName);
            fos = new FileOutputStream(newFile);
            int len;
            while ((len = zis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
            fos.close();
            zipEntry = zis.getNextEntry();
        }
        zis.closeEntry();
        zis.close();
    } catch (IOException | NullPointerException e) {
        e.printStackTrace();
    }
    st.setText("Status: Ready");


}

结果如下:39ko temp.zip 文件似乎已损坏。它不会解压缩(显然)。我尝试了来自多个域的许多链接,仍然是同样的问题...

编辑:尝试了不同的方法...同样的错误..新代码:

        URL url = new URL(link);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        InputStream in = connection.getInputStream();
        FileOutputStream out = new FileOutputStream("download.zip");
        copy(in, out, 1024);
        out.close();
public static void copy(InputStream input, OutputStream output, int bufferSize) throws IOException {
    byte[] buf = new byte[bufferSize];
    int n = input.read(buf);
    while (n >= 0) {
        output.write(buf, 0, n);
        n = input.read(buf);
    }
    output.flush();
}

我评论了解压部分,还是一样...结论:下载是问题。

【问题讨论】:

  • 是什么让您认为这个问题与 JavaFX 有关系?如果在控制台应用程序中运行,完全相同的代码是否有效?
  • 我并不是说它与 javafx 有任何关系...我说我必须使用 Platform.runLater() 所以没有人问我为什么这样做。它很可能在控制台中做同样的事情。
  • 你在 while 循环的顶部做一个 if(fileName.contains()) 检查,它可以继续,但是 zipEntry = zis.getNextEntry();位于循环的底部,因此不会调用 zis.getNextEntry()。它是否陷入了无限循环?
  • 您遇到的另一个问题是其中两个线程无法同时执行,因为固定文件名test.zip。你需要让它动态化。如果您不需要实际的 .zip 文件,直接从 URL 连接的输入流中解压缩会更有效。
  • 附注:不要在runLater() 任务中下载和解压缩文件。在后台线程中执行此操作。只有在下载并解压缩文件后,该任务才应调用 runLater() 来更新 UI。 JavaFX 应用程序线程是处理所有 GUI 事件的地方。使用它来执行网络 IO 和其他不可靠、可能持续时间较长的任务会使 UI 无响应。

标签: java multithreading javafx download


【解决方案1】:

您在 while 循环的顶部执行 fileName.contains() 检查,可以 continue,返回到 while 循环的开头。但是zipEntry = zis.getNextEntry() 位于循环的底部,因此在这些情况下不会调用它。看起来它陷入了无限循环

     while(zipEntry != null) {
        fileName = zipEntry.getName();
        if(fileName.contains("##TEMP##")) continue;
        if(fileName.contains("MACOSX")) continue;

        // unzipping code

        zipEntry = zis.getNextEntry(); // never happens when filename  contains ##TEMP## or MACOSX 
    }

getNextEntry() 代码移动到循环顶部并从变量声明中删除第一个调用..

     ZipEntry zipEntry;

     while((zipEntry = zis.getNextEntry()) != null) {
        fileName = zipEntry.getName();
        if(fileName.contains("##TEMP##")) continue;
        if(fileName.contains("MACOSX")) continue;

        // unzipping code
    }

【讨论】:

  • 试过了,还是不行。我什至在没有fileName.contains()的情况下尝试过,但还是没有运气...
  • 你能不能输入一些登录信息来看看它在代码中的不同点做了什么。我担心的是您将 zip 中的文件名直接传递到 new File(fileName);它可能无法在该路径创建文件。这也是一个很大的安全风险。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
相关资源
最近更新 更多