2

I'm getting an exception while walking a file tree of a VFS (virtual file system) of a zip file using java nio, here is my code:

public static void list(String zipFilePath) throws IOException{
    FileSystem fs = FileSystems.newFileSystem(Paths.get(zipFilePath), null);
    Path startPath = fs.getPath("/");

    Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            System.out.println("Dir : " + dir);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            System.out.println("\t->File : " + file);
            return FileVisitResult.CONTINUE;
        }
    });
}

the exception says that a file does not exists, but I've decompress the archive (zip), and the file is there... any idea why?

here is the exception:

java.nio.file.NoSuchFileException: /Dir1/Dir2/Dir3/Dir4/ExcelFile.xlsm
at com.sun.nio.zipfs.ZipPath.getAttributes(ZipPath.java:657)
at com.sun.nio.zipfs.ZipFileSystemProvider.readAttributes(ZipFileSystemProvider.java:285)
at java.nio.file.Files.readAttributes(Files.java:1669)
at java.nio.file.FileTreeWalker.walk(FileTreeWalker.java:105)
at java.nio.file.FileTreeWalker.walk(FileTreeWalker.java:199)
at java.nio.file.FileTreeWalker.walk(FileTreeWalker.java:69)
at java.nio.file.Files.walkFileTree(Files.java:2585)
at java.nio.file.Files.walkFileTree(Files.java:2618)

BTW: The code DOES work, but it crash with certain files

Ordiel
  • 2,442
  • 3
  • 36
  • 52
  • Is there any pattern to the files it fails on? Always xlsm? Any passwords in use in the zip files? – Jon Bright Feb 01 '13 at 20:56
  • no, no that i can see at least... – Ordiel Feb 02 '13 at 19:03
  • Did you ever figure this out? I'm stumped on it too. From http://stackoverflow.com/questions/14436032/why-is-java-7-files-walkfiletree-throwing-exception-on-encountering-a-tar-file-o comments my current guess is that it's calling some kind of native windows getAttributes *in error* or something...jdk bug? jdk bug just on windows? are you on windows? – rogerdpack Aug 28 '13 at 18:15
  • Yes, let me add my answer, thanks for reminding me this one – Ordiel Aug 29 '13 at 13:12

2 Answers2

7

When you're using a ZipFileSystem it manages the paths as they where stored (remember that there are no folders inside a zip, just files, and each file is identified by its complete path name, up to the level of the directory selected to be zipped, therefore it is not "myTextFile.txt" inside the zip its named as "/Folder 1/Folder 2/myTextFile.txt"); Using Path always return the name using the "standard" file separator (*nix OS), but if your zip archive was stored using the windows file separator, it just fails, this does not happend if you use the same method to create your file that you will use to open, I mean, if you use ZipOutputStream and ZipEntry to compress your file, and then ZipFileSystem to decompress it, it fails if you are not careful with the file separators.

Now, you may say, why does it fails only with certain files inside the zip in your case then, well, when I was working with the software causing this problem, I was zipping the files using ZipOutputStream ZipEntry, and Path, I "manually" navigating through the file tree, until I reach a file, and to add a zip entry I was using Path and then adding to the String name the name of file to be saved adding a separator by concatenating it (+"/"+).

You may say "OK, I understand what you are saying, but, why in hell was it working when you decompress the archive using a third party software?", thats an easy one, it is because they replace all the file separators the could find in each file name to ensure they are using allways the same file separator, whether '/' or '\'...

Lessons Learned: DO NOT mix stuff!!! use one single method to compress and decompress your archives, or ENSURE that all the info is being stored under the same "name", ensure that you are using the exact same file separators every time.

Ordiel
  • 2,442
  • 3
  • 36
  • 52
  • I was doing `Files.walk(root, 1).filter(...).findAny()` (where `root` is a directory from a ZIP filesystem) and getting `java.io.UncheckedIOException: java.nio.file.NoSuchFileException`. It turned out the cause was backslashes in the filenames in the ZIP file. This question and answer really helped me out - four years after it was asked :) – dave Nov 22 '17 at 04:07
  • "DO NOT mix stuff" But what if I have to process third party zips file? – T-Gergely Mar 27 '18 at 11:46
  • You will need to accomodate your logic to handle both slash types, I would obtain the list of the files on the zip file. Lets imagine that the one that originally created the file was an idiot and decided to store the file as `\folder1/folder2/folder3\myfile.txt`; this is a terrible mess, but in order to easily handle this case what I would do would be to create a map containing the *"pretty"* name, and pointing to the shitty name, for the previous example `/folder1/folder2/folder3/myfile.txt` should point to `\folder1/folder2/folder3\myfile.txt` – Ordiel Apr 02 '18 at 22:41
  • faced similar issue "+ File.separator +" helped java.io.FIles – SDV Jul 01 '21 at 07:33
  • @SDV you should check [this other question](https://stackoverflow.com/questions/13846000/file-separators-of-path-name-of-zipentry) I asked, I already went down that path and [File.separator](https://docs.oracle.com/javase/7/docs/api/java/io/File.html#separator) is system dependent, while the zip file specification clearly defines the correct separator within a zip – Ordiel Jul 01 '21 at 17:06
0

I know this is an old post but exactly this just happened to me. All my zipfiles are created by a third party, namely Microsoft Word. I cannot even catch the exception to find out which input file from the zip is causing the NoSuchFileException, because the Java compiler says:

NoSuchFileException cannot be resolved to a type

casgage
  • 529
  • 1
  • 7
  • 18
  • Hi, not such thing as old post if people are still reading it ;) Try importing that exception, it should be there since is part of Java SE: `import java.nio.file.NoSuchFileException;` Tip: maybe you were down voted since this was maybe better as a comment – Ordiel Jul 28 '21 at 14:47