7

I have code that extracts some specific large (about 15k entries) binary serialized file archive to folder on disk.

public void extractExact(Path absolutePath, DoubleConsumer progressConsumer) throws IOException
{
    ...
    // Extract to file channel
    try (final FileOutputStream fos = new FileOutputStream(absolutePath.toFile()))
    {
        PakExtractor.Extract(pakFile, Entry, fos.getChannel(), progressConsumer);
    }
 }

extractExact function calls for every entry in archive.

after this, if I try to call Files.delete(<archive_file_path>) method - I will get an exception:

java.nio.file.FileSystemException: The process cannot access the file because it is being used by another process.

I checked my archive file in Process Explorer search and it says that I have ~15k file openings by my java.exe (as many as the files in the archive)

this happens only in windows (jdk1.8.0_162). On Linux I don't have any problems with "zombie" opened files.

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Could be some service in Windows, which is indexing/analyzing the files? Some desktop search indexing, antivirus, etc? – NeplatnyUdaj Apr 16 '19 at 14:48
  • 1
    Maybe you need to call `fos.flush()` before the next call? It could be that there is still something to write. – Sascha Apr 16 '19 at 15:01
  • Your try-with-resources usage is correct. I have many times observed Windows keeping a lock on a file for some seconds after it was closed by a program, even non-Java programs (but I am having trouble finding an existing Stack Exchange question about it). – VGR Apr 16 '19 at 15:02
  • 3
    But why this detour? Just use `try(FileChannel ch = FileChannel.open(absolutePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { … }`, no need for `.toFile()`, no need for `.getChannel()`. And if you want to delete the file right afterwards, you can specify `StandardOpenOption.DELETE_ON_CLOSE` right at the `open` call. – Holger Apr 16 '19 at 16:34
  • @NeplatnyUdaj I not sure because this happens on all windows machines (with or without antivirus). Anyway, Process Explorer shows that files used by java.exe. – Nikita Mirošničenko Apr 17 '19 at 08:04
  • @Sascha it does not make any sense, the problem is still there :( – Nikita Mirošničenko Apr 17 '19 at 08:09
  • @Holger thank you, code more fluent now :) – Nikita Mirošničenko Apr 17 '19 at 08:11
  • Can this thing happens because of I pass my channel as argument to another procedure? Anyway, what I found: if I toggle breakpoint at exception and evaluate next code `((FileChannelImpl) fileChannel.fd.closed` result will be false, I think this is not normal – Nikita Mirošničenko Apr 17 '19 at 08:14
  • 1
    The breakpoint should be in the `finally`part of your `try`. – Sascha Apr 17 '19 at 12:05

1 Answers1

3

Finally - we found the solution. Many thanks to @Netherwire. FileChannel class have map method that does some implicit copy operations with file descriptors, so be careful when use it. Here is more information.

  • 1
    I encountered scenarios where I used the `DELETE_ON_CLOSE` option mentioned in [my previous comment](https://stackoverflow.com/questions/55710865/fileoutputstream-try-with-resouces-doent-close-file-descriptor?noredirect=1#comment98106303_55710865) together with `map`. The good thing about it, is, when there are still existing mappings preventing deletion at `close()` time, the file will get deleted when the mappings are cleaned or at JVM exit time as a last resort. – Holger Apr 18 '19 at 11:17