Как вы можете создать новый zip-файл в Java и добавить в него большой каталог файлов? - PullRequest
1 голос
/ 18 июня 2019

Я пытаюсь добавить каталог файлов в zip.Каталог составляет около 150 файлов.В нескольких файлах по 5–75 я получаю сбой с сообщением об ошибке "The process cannot access the file because it is being used by another process."

Я попытался отложить, что может помочь, но, безусловно, не устраняет ошибку.

Использованиекод из: Можно ли создать НОВЫЙ zip-файл, используя файловую систему java?

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);
    }
}

1 Ответ

0 голосов
/ 19 июня 2019

Не могу обещать, что это является причиной вашей проблемы, но ваш код сжимает файлы в ZIP-файл странным или, по крайней мере, неэффективным образом.В частности, вы открываете новый FileSystem для каждого отдельного файла, который вы хотите сжать.Я предполагаю, что вы делаете это таким образом, потому что это то, с чем вы связаны.Однако , который отвечает , сжимает только один файл, в то время как вы хотите сжать несколько файлов одновременно.Вы должны держать FileSystem открытым в течение всего времени сжатия вашего каталога.

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 используется точно так же, какmaxDepth находится в Files#walkFileTree.

Примечание: Если вы когда-либо заботитесь только о файлах в самом каталоге (т.е.не хотите рекурсивно обходить дерево файлов), тогда вы можете использовать Files#list(Path).Не забудьте закрыть Stream, когда закончите с ним.

Возможно, вы открываете и закрываете FileSystem снова и снова, это вызывает ваши проблемы, и в этом случае вышеуказанное должно решитьвопрос.

...