0

I ran into an unexpected case while creating a zip file using Java's FileSystem API, where the disk space ran out in the process of creating the file.

Because of a coding error, the source files where deleted even though the zip file failed to be created. I have salvaged a tmp-file from the server, and am wondering if I can use the FileSystem API to salvage the data by loading the temporary file and finish the write.

The code used to write a zip file looks like this:

    final Map<String, String> env = new HashMap<>();
    env.put("create", "true");
    final String zipArchiveFilename = System.currentTimeMillis() + ".zip";
    final URI uri = URI.create("jar:file:" + zipDir.getAbsolutePath() + "/" + zipArchiveFilename);
    final List<Path> files = ...;

    try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
        for (Path file : files) {
            Files.copy(file, zipfs.getPath(file.toFile().getAbsolutePath().replace(dir.getAbsolutePath(), "")), StandardCopyOption.REPLACE_EXISTING);
        }
    } catch (IOException e) {
        Logger.error("Failed to create zip file:", e);
    }
Nicholas K
  • 15,148
  • 7
  • 31
  • 57
Chris
  • 282
  • 2
  • 9

1 Answers1

0

It could be tried as follows:

    Path path = Paths.get("C:\\Users\\... .zip");
    final URI uri = URI.create("jar:" + path.toUri().toString());

    Map<String, Object> env = new HashMap<>();
    try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
        Path root = zipfs.getPath("/");
        final Path targetDir = Paths.get("C:/Users/Joop/limbo");
        Files.createDirectories(targetDir);
        final AtomicInteger fno = new AtomicInteger();
        Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                System.out.println("Failed: " + file);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                String name = fno.incrementAndGet() + "-"
                        + file.getFileName().toString().replaceAll("[^-.\\w]+", "");
                Path targetFile = targetDir.resolve(name);
                System.out.println("+ " + file + " - " + targetFile);
                Files.copy(file, targetFile, StandardCopyOption.REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }

        });
    }

The URI I did not take from the File but from the File.toURI to get rid of the backslash on Windows.

The file name may be corrupted or have the wrong encoding, hence the conversion of the file name.

I am unsure whether a zip file system will do.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Thanks for the tip, but sadly it results in a `java.util.zip.ZipError: zip END header not found` exception. – Chris Sep 27 '18 at 14:52
  • Then a ZipInputStream or even a ZipFile seems best; before reaching the end every previous ZipEntry should be readable. – Joop Eggen Sep 27 '18 at 15:02
  • I got a great comment pointing to `zip -FF bad.zip --out good.zip` -> That worked great – Chris Sep 27 '18 at 15:07