如何用java进行多线程解压缩大文件夹 - 首选java8?

问题描述 投票:8回答:2

参考:qazxsw poi

我正在尝试解压缩5GB压缩文件,平均需要大约30分钟,这对我们的应用来说很重要,我正在努力减少时间。

我已经尝试了很多组合,改变了缓冲区大小(默认情况下我的写入块是4096字节),改变了NIO方法,库,所有结果都是相同的。

仍然没有尝试的一件事是按块分割压缩文件,因此通过多线程块读取它。

代码段是:

http://www.pixeldonor.com/2013/oct/12/concurrent-zip-compression-java-nio/

而runnable是:

  private static ExecutorService e = Executors.newFixedThreadPool(20);
  public static void main(String argv[]) {
        try {
            String selectedZipFile = "/Users/xx/Documents/test123/large.zip";
            String selectedDirectory = "/Users/xx/Documents/test2";
            long st = System.currentTimeMillis();

            unzip(selectedDirectory, selectedZipFile);

            System.out.println(System.currentTimeMillis() - st);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


public static void unzip(String targetDir, String zipFilename) {
    ZipInputStream archive;
            try {
                List<ZipEntry> list = new ArrayList<>();
                archive = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFilename)));
                ZipEntry entry;
                while ((entry = archive.getNextEntry()) != null) {
                    list.add(entry);
                }

                for (List<ZipEntry> partition : Lists.partition(list, 1000)) {
                    e.submit(new Multi(targetDir, partition, archive));
                }
            } catch (Exception e){
                e.printStackTrace();
            }
}

但由于理由,它只存储没有文件内容的目录......

我的问题是:对于上面提到的“压缩”文章的方式,在大型zip文件上制作多线程块的正确方法是什么?

java multithreading java-8 zip nio
2个回答
3
投票

static class Multi implements Runnable { private List<ZipEntry> partition; private ZipInputStream zipInputStream; private String targetDir; public Multi(String targetDir, List<ZipEntry> partition, ZipInputStream zipInputStream) { this.partition = partition; this.zipInputStream = zipInputStream; this.targetDir = targetDir; } @Override public void run() { for (ZipEntry entry : partition) { File entryDestination = new File(targetDir, entry.getName()); if (entry.isDirectory()) { entryDestination.mkdirs(); } else { entryDestination.getParentFile().mkdirs(); BufferedOutputStream output = null; try { int n; byte buf[] = new byte[BUFSIZE]; output = new BufferedOutputStream(new FileOutputStream(entryDestination), BUFSIZE); while ((n = zipInputStream.read(buf, 0, BUFSIZE)) != -1) { output.write(buf, 0, n); } output.flush(); } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally { try { output.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } } } 是单个数据流,不能拆分。

如果你想要多线程解压缩,你需要使用ZipInputStream。使用Java 8,您甚至可以免费获得多线程。

ZipFile

您可能还想查看public static void unzip(String targetDir, String zipFilename) { Path targetDirPath = Paths.get(targetDir); try (ZipFile zipFile = new ZipFile(zipFilename)) { zipFile.stream() .parallel() // enable multi-threading .forEach(e -> unzipEntry(zipFile, e, targetDirPath)); } catch (IOException e) { throw new RuntimeException("Error opening zip file '" + zipFilename + "': " + e, e); } } private static void unzipEntry(ZipFile zipFile, ZipEntry entry, Path targetDir) { try { Path targetPath = targetDir.resolve(Paths.get(entry.getName())); if (Files.isDirectory(targetPath)) { Files.createDirectories(targetPath); } else { Files.createDirectories(targetPath.getParent()); try (InputStream in = zipFile.getInputStream(entry)) { Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING); } } } catch (IOException e) { throw new RuntimeException("Error processing zip entry '" + entry.getName() + "': " + e, e); } } ,它使用this answer来访问zip文件内容,以获得真正的Java 8体验。


0
投票

这里是一个利用FileSystem的并行版本。你应该稍微调整一下(例如实际使用流媒体,添加错误处理)。但它应该是一个不错的开始。

FileSystem
© www.soinside.com 2019 - 2024. All rights reserved.