12

I'm having some problems deleting a file in Windows with java. For some reason, java is keeping a lock on my file, and I don't know why. Here is my code:

private byte[] getFileByteArray(File file) {
    try {
        RandomAccessFile raf = new RandomAccessFile(file, "r");
        FileChannel channel = raf.getChannel();
        try {

            ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
            byte[] bt = new byte[buffer.remaining()];
            buffer.get(bt);
            channel.close();
            raf.close();
            file.delete();
            return bt;

        } catch (Exception ex) {
            //Logger.getLogger(ConnectionImpl.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println(ex.toString());
        }

    } catch (FileNotFoundException ex) {
        Logger.getLogger(ConnectionImpl.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

file.delete(), as well as trying manually in Explorer refuses to delete the file as it's still in use. All seems well in Linux though.

Am I missing a close() somehwhere? I can confirm that the method which makes the file in the first place is closing the file, as I can delete the file before running the above code using file.delete()

Extra Info: The code above is part of a method called getFileByteArray(File file) and is being called like this:

public byte[] createReport(int id) {

    Report report = new Report();
    String filename = report.CreateReport(id);
    return getFileByteArray(new File(filename));
}

Thanks

Update: I managed to fix the issue by reading the file kilobyte by kilobyte into the byte array using ByteArrayOutputStream

As a poster below mentioned, there is a known bug in Java in that Windows has issues with file mapping.

jtnire
  • 1,348
  • 5
  • 21
  • 32

2 Answers2

21

This is a known Bug in Java on Windows, please see Bug #4715154

Sun evaluated the problem and closed the bug with the following explanation:

We cannot fix this. Windows does not allow a mapped file to be deleted. This problem should be ameliorated somewhat once we fix our garbage collectors to deallocate direct buffers more promptly (see 4469299), but otherwise there's nothing we can do about this.

mhaller
  • 14,122
  • 1
  • 42
  • 61
  • Well, I tried System.gc() on my Win7, but it does not work, even with NULLifying and sleeping. I would go with the Do-Not-Use-NIO workaround in this case. – mhaller Nov 14 '10 at 20:16
  • Do not use NIO? Can you give an example please? – jtnire Nov 14 '10 at 20:20
  • 1
    Just write to [`ByteArrayOutputStream`](http://download.oracle.com/javase/6/docs/api/java/io/ByteArrayOutputStream.html) the usual way. When finished, just call its `toByteArray()` method to grab the `byte[]`. – BalusC Nov 14 '10 at 20:38
  • 1
    System.gc() will eventually work. I stumbled across this bug and wrote a loop which attempts `file.delete()`, calls `System.gc()` and then `Thread.sleep(2000)`. It seems to consistently delete the file after about 3 loops. I'll probably add a loop counter here and leave it at that. Beware that mapping the same file after deleting and recreating can also cause some problems on Windows. I'd recommend the "no-NIO" route if this is something you would need to do. – sarumont Feb 14 '12 at 23:45
  • I just wasted hours (if not days) of my life tracking down this locking issue. You'll get locks even if you're just using `Paths.get` or `File.list`. Do yourself a favour and avoid java.nio if you're running on Windows. – Glen Apr 03 '20 at 17:30
  • WIth `ByteArrayOutputStream bos = new ByteArrayOutputStream(0); FileOutputStream fos = new FileOutputStream(file); bos.writeTo(fos); fos.close();` I ended up with the file I want to delete having size 0 kb. But I still don't know how to delete it afterwards. Tips welcome. – msoutopico Sep 05 '20 at 10:44
1

Adding to mhaller's answer

And translating sarumont's comment into code

This should/may work.

private static void deleteMappedFilesIfExists(Path path) throws IOException {
    while (true) {
        try {
            Files.deleteIfExists(path);
            break;
        } catch (AccessDeniedException e) {
            System.gc();
        }
        //Add delay if needed.
    }
}
  • 1
    This didn't work for me, the lock/handle would remain. Going to the file in Windows Explorer would give an access denied error until the VM exited at which point the directory would disappear. I'm using JDK11, maybe it works on prior versions. – Glen Apr 03 '20 at 17:37