0

I would like to hava a static Path property to be scanned for children files, this Path references a zip file and I can't close it because it will be referenced randomly. At some points I need to write into the zip file. The problem is I don't want to close the file system, because the Path property need to be open for future reading, and if I don't close it I can't see the written changes. If I try to create another filesystem referencing the same path I get FileSystemAlreadyExistsException. I could close the fs after writing and then open it again, but some one could try to read the Path at this moment. There is a workaround ? Why don't I need to close the default FileSystem to see the written files and I do need with the zip FileSystem?

    public static void copyTree(final Path source, final Path targetPath) throws IOException {
        FileSystem fs = FileSystems.getFileSystem(targetPath.toUri());

        Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                Files.copy(dir, targetPath, StandardCopyOption.REPLACE_EXISTING);
                return super.preVisitDirectory(dir, attrs);
            }
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.copy(file, targetPath, StandardCopyOption.REPLACE_EXISTING);
                return super.visitFile(file, attrs);
            }

        });

        //if I don't close the FileSystem here the changes won't appear.
        fs.close();
    }
Gus
  • 942
  • 9
  • 32
  • `fs` is completely useless in your example, it does nothing and is not being used by anything except `close` - basically, you open a file and close it again without reading it explicitly. – specializt Jan 18 '17 at 13:02

1 Answers1

0

You dont close a "file system", you may close a FILE - these are completely different things. FileSystemAlreadyExistsException is simply ill-named - one can not close / unmount filesystems entirely with java, AFAIK, please stop using the word "filesystem" for files, its very confusing.

To answer your question : if i managed to decipher it correctly, you were wondering about access to one file from several threads, is that just about right?

In that case the most simple solution will be : wrap the access to your file into a new class, make the class a singleton and every write-method synchronized. That way every write-operation will block until the last one finished - with an additional method which closes the file you can even shutdown your application in a controlled manner : http://docs.oracle.com/javase/7/docs/api/java/io/Closeable.html, you may also use try-with-resources for nio method-calls which throw exceptions

I think this small example for a .property-file might carry the idea : Load Properties File in Singleton Class

Community
  • 1
  • 1
specializt
  • 1,913
  • 15
  • 26
  • 1
    Thanks for answering, sorry for the confusion. I was talking about closing the FileSystem object, not the file, I've updated the question with some code in order to explain better. – Gus Oct 27 '14 at 11:45
  • I could synchronize all methods that write to the filesystem, but the problem is I would need to synchronize the read methods too, because I need to close the fs object right after writing to it. – Gus Oct 27 '14 at 11:48
  • ... yes, thats pretty much what you need to do. In fact you were advised to lock the whole file at the beginning of each read-operation and only unlock after it has been written / closed again - thats the only way to avoid racing conditions. I would recommend using a semaphore - these are pretty efficient and easy to use. – specializt Oct 27 '14 at 11:56
  • I would have to recreate the FileSystem just to check if a directory is empty ? I would have to synchronize access to different files if they are in the same fs too .. – Gus Oct 27 '14 at 12:09
  • I mean, this is worse than synchronizing access to just one file, its the whole filesystem object that have to be synchronized, closed and recreated every time. Seems too much overhead. – Gus Oct 27 '14 at 12:14
  • welcome to the world of HDD I/O. You could implement a class which gathers all of the changed files, write them individually and whatnot - but that will get SERIOUSLY complex – specializt Oct 27 '14 at 12:22
  • I may be too persistent but using the java.util.File class don't require synchronizing access to different files. This is because of the generalization of nio ? Maybe this is why I don't have to close the FileSystem using nio default FileSystem but have to do it with ZipFileSystem ? – Gus Oct 27 '14 at 12:47
  • http://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html says this: `File systems are safe for use by multiple concurrent threads. The close method may be invoked at any time to close a file system but whether a file system is asynchronously closeable is provider specific and therefore unspecified. In other words, if a thread is accessing an object in a file system, and another thread invokes the close method then it may require to block until the first operation is complete.` – Gus Oct 27 '14 at 12:56
  • 2
    *You dont close a "file system"*: I beg to differ. Infact `FileSystem.close()` *needs* to be called for `ZipFileSystem` otherwise opening the same jar file in future will result in `FileSystemAlreadyExistsException`. – antak Jan 10 '17 at 06:42
  • you obviously dont know the difference between a [filesystem](https://en.wikipedia.org/wiki/File_system) and [files](https://en.wikipedia.org/wiki/Computer_file). Maybe try reading the whole topic before you start assuming random things – specializt Jan 11 '17 at 21:35
  • btw : he is not using `FileSystem`, hes using the **method** `walkFileTree` - and i cant even finde a single piece of information about the thread safety of this method ... its always safe to assume that something is **not** threadsafe until proven otherwise – specializt Jan 18 '17 at 13:01