Il pacchetto java.nio
ha un bellissimo modo di gestire i file zip trattandoli come file system. Questo ci permette di trattare i contenuti dei file zip come i soliti file. Pertanto, è possibile realizzare zippare un'intera cartella semplicemente utilizzando Files.copy
per copiare tutti i file nel file zip. Dal momento che le sottocartelle devono essere copiati così, abbiamo bisogno di un visitatore:Zippare una cartella enorme utilizzando un file ZipFile provoca l'errore OutOfMemoryError
private static class CopyFileVisitor extends SimpleFileVisitor<Path> {
private final Path targetPath;
private Path sourcePath = null;
public CopyFileVisitor(Path targetPath) {
this.targetPath = targetPath;
}
@Override
public FileVisitResult preVisitDirectory(final Path dir,
final BasicFileAttributes attrs) throws IOException {
if (sourcePath == null) {
sourcePath = dir;
} else {
Files.createDirectories(targetPath.resolve(sourcePath
.relativize(dir).toString()));
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
Files.copy(file,
targetPath.resolve(sourcePath.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
}
Si tratta di una "directory ricorsivamente copia" semplice visitatore. È usato per copiare una directory in modo ricorsivo. Tuttavia, con l'ZipFileSystem
, possiamo anche usare per copiare una directory in un file zip, in questo modo:
public static void zipFolder(Path zipFile, Path sourceDir) throws ZipException, IOException
{
// Initialize the Zip Filesystem and get its root
Map<String, String> env = new HashMap<>();
env.put("create", "true");
URI uri = URI.create("jar:" + zipFile.toUri());
FileSystem fileSystem = FileSystems.newFileSystem(uri, env);
Iterable<Path> roots = fileSystem.getRootDirectories();
Path root = roots.iterator().next();
// Simply copy the directory into the root of the zip file system
Files.walkFileTree(sourceDir, new CopyFileVisitor(root));
}
Questo è quello che io chiamo un modo elegante di zippare un'intera cartella. Tuttavia, quando si utilizza questo metodo su una cartella enorme (circa 3 GB) ricevo uno OutOfMemoryError
(spazio heap). Quando si utilizza una normale libreria di gestione zip, questo errore non viene generato. Pertanto, sembra che il modo in cui lo ZipFileSystem
gestisce la copia sia molto inefficiente: troppo gran parte dei file da scrivere viene conservata in memoria, pertanto si verifica OutOfMemoryError
.
Perché è questo il caso? L'utilizzo di ZipFileSystem
è generalmente considerato inefficiente (in termini di consumo di memoria) o sto facendo qualcosa di sbagliato qui?
dispiace, ma questa risposta non aiuta affatto. 1) So come aumentare la dimensione dell'heap, questa non è la domanda. 2) Che cos'è "file system di memoria" o "sistema di file su disco"? 3) Il metodo non è concomitante come si dovrebbe vedere dal codice – gexicide
@gexicide Si prega di verificare la mia risposta e se risolve il problema (come ha fatto per gli altri) si prega di contrassegnare come la risposta corretta. Grazie. –