Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RandomAccessFile Vs NIO Channel

I am trying to understand the following behavior. My older code,

String path = "C:/temp/sample.txt";
String mode= "rw";
FileChannel channel = new RandomAccessFile(path, mode).getChannel();
// some code to write to this file

// finally delete
File file = new File(path);
boolean isDeleted = file.delete();
System.out.println("Is Deleted - " + isDeleted);

O/P - Is Deleted - false

Only if i do a "channel.close();" before i delete the file. Does it delete the file and return true.

Newer replaced code,

String path = "C:/temp/sample.txt";
FileChannel fChannel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
// some code to write to this file

// finally delete
File file = new File(path);
boolean isDeleted = file.delete();
System.out.println("Is Deleted - " + isDeleted);

O/P - Is Deleted - true

But this does not delete the file until the application exits. If i use "fChannel.close()", it will delete it immediately.

Few questions,

  1. Why different behaviors, i understand both are different types, i.e. RA vs Seekable Channel. But not sure, why delete should behave differently.
  2. In the newer implementation, if it does not delete the file until, the application exits, then it should either return false (i.e. will not delete, until close is called) or then delete immediately.

I don't know if i have hit a bug or missing something. Any pointers can help.

Thanks

like image 336
Victor Avatar asked Nov 10 '22 22:11

Victor


1 Answers

From the specification of RandomAccessFile.getChannel():

The position of the returned channel will always be equal to this object's file-pointer offset as returned by the getFilePointer method. Changing this object's file-pointer offset, whether explicitly or by reading or writing bytes, will change the position of the channel, and vice versa. Changing the file's length via this object will change the length seen via the file channel, and vice versa.

In other words, the returned channel and the RandomAccessFile maintain a bidirectional relationship and both are either open or closed. So in this regard, it’s not the FileChannel but the RandomAccessFile, which is still open while the channel is open, that keeps the File locked.

When you call close on such a FileChannel it will close the associated RandomAccessFile as well, letting nothing remain within the JRE preventing the delete operation.

In contrast, when creating a FileChannel via FileChannel.open it doesn’t have an associated FileInputStream, FileOutputStream, nor RandomAccessFile and doesn’t prevent a File.delete operation.

So when there is nothing within the JVM/JRE preventing the delete operation, it will exhibit the behavior of the underlying operating system, e.g. on Microsoft Windows:

DeleteFile function

Deletes an existing file.

The DeleteFile function marks a file for deletion on close. Therefore, the file deletion does not occur until the last handle to the file is closed. Subsequent calls to CreateFile to open the file fail with ERROR_ACCESS_DENIED.

This is exactly the observed behavior. You don’t need to exit the JVM, closing the FileChannel is enough to complete the deletion.

like image 196
Holger Avatar answered Nov 14 '22 23:11

Holger