首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在Java中创建一个新的zip文件并向其中添加一个包含大量文件的目录?

如何在Java中创建一个新的zip文件并向其中添加一个包含大量文件的目录?
EN

Stack Overflow用户
提问于 2019-06-19 02:38:26
回答 1查看 175关注 0票数 1

我正在尝试将文件的目录添加到压缩包中。该目录大约有150个文件。在几个5-75个文件中,我不断收到崩溃并显示错误消息"The process cannot access the file because it is being used by another process."

我尝试了延迟,这可能有帮助,但肯定不能解决错误。

使用来自:Is it possible to create a NEW zip file using the java FileSystem?的代码

代码语言:javascript
复制
final File folder = new File("C:/myDir/img");
for (final File fileEntry : folder.listFiles()) {
    if (fileEntry.isDirectory()) {
        continue;
    }
    else {
        String filename = fileEntry.getName();
        String toBeAddedName = "C:/myDir/img/" + filename;
        Path toBeAdded = FileSystems.getDefault().getPath(toBeAddedName).toAbsolutePath();
        createZip(zipLocation, toBeAdded, "./" + filename);
        System.out.println("Added file " + ++count);
        //Delay because 'file in use' bug
        try { Thread.sleep(1000); } //1secs
        catch (InterruptedException e) {}
    }
}

public static void createZip(Path zipLocation, Path toBeAdded, String internalPath) throws Throwable {
    Map<String, String> env = new HashMap<String, String>();
    //Check if file exists.
    env.put("create", String.valueOf(Files.notExists(zipLocation)));
    //Use a zip filesystem URI
    URI fileUri = zipLocation.toUri();  //Here
    URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);
    System.out.println(zipUri);
    //URI uri = URI.create("jar:file:"+zipLocation);    //Here creates the zip
    //Try with resource
    try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, env)) {
        //Create internal path in the zipfs
        Path internalTargetPath = zipfs.getPath(internalPath);
        //Create parent dir
        Files.createDirectories(internalTargetPath.getParent());
        //Copy a file into the zip file
        Files.copy(toBeAdded, internalTargetPath, StandardCopyOption.REPLACE_EXISTING);
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-20 03:14:03

我不能保证这就是您问题的原因,但是您的代码以一种奇怪的方式(至少是低效的方式)将文件压缩为ZIP文件。具体地说,您将为每个要压缩的文件打开一个新的FileSystem。我假设你是这样做的,因为你链接的Q&A就是这样做的。但是,that answer只压缩一个文件,而您希望同时压缩多个文件。您应该在压缩目录的整个过程中保持FileSystem处于打开状态。

代码语言:javascript
复制
public static void compress(Path directory, int depth, Path zipArchiveFile) throws IOException {
    var uri = URI.create("jar:" + zipArchiveFile.toUri());
    var env = Map.of("create", Boolean.toString(Files.notExists(zipArchiveFile, NOFOLLOW_LINKS)));

    try (var fs = FileSystems.newFileSystem(uri, env)) {
        Files.walkFileTree(directory, Set.of(), depth, new SimpleFileVisitor<>() {

            private final Path archiveRoot = fs.getRootDirectories().iterator().next();

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                // Don't include the directory itself
                if (!directory.equals(dir)) {
                    Files.createDirectory(resolveDestination(dir));
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.copy(file, resolveDestination(file), REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }

            private Path resolveDestination(Path path) {
                /*
                 * Use Path#resolve(String) instead of Path#resolve(Path). I couldn't find where the
                 * documentation mentions this, but at least three implementations will throw a 
                 * ProviderMismatchException if #resolve(Path) is invoked with a Path argument that 
                 * belongs to a different provider (i.e. if the implementation types don't match).
                 *
                 * Note: Those three implementations, at least in OpenJDK 12.0.1, are the JRT, ZIP/JAR,
                 * and Windows file system providers (I don't have access to Linux's or Mac's provider
                 * source currently).
                 */
                return archiveRoot.resolve(directory.relativize(path).toString());
            }

        });
    }
}

注意: depth参数的用法与maxDepthFiles#walkFileTree中的用法完全相同(https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/nio/file/Files.html#walkFileTree(java.nio.file.Path,java.util.Set,int,java.nio.file.FileVisitor%29)

注意:如果你只关心目录本身的文件(也就是不想递归遍历文件树),那么你可以使用。使用完the_ Stream后,不要忘记关闭它。

可能是您反复打开和关闭FileSystem导致了您的问题,在这种情况下,上述方法应该可以解决问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56655156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档