Reputation: 18615
I am looking for a way to read the content of a file in Java without updating the last access time of the file. In C on Linux this is achieved by passing the O_NOATIME
flag to open
, and I'm sure other languages and platforms have similar mechanisms.
I'm using Files.newInputStream
which has various options that can be passed, but none that appear to match O_NOATIME
.
Is there a way to read the content of a file in Java on a unix-like platform without updating the last access time of the file?
Upvotes: 2
Views: 290
Reputation: 5200
I don't think there's a way to do this in Java (apart from implementing it natively with JNI OFC). I grepped JDK sources at Github for instances of O_NOATIME
and didn't get any hits.
If you peek into the UnixChannelFactory class you can see the Flags class which, I think, lists all supported options:
protected static class Flags {
boolean read;
boolean write;
boolean append;
boolean truncateExisting;
boolean noFollowLinks;
boolean create;
boolean createNew;
boolean deleteOnClose;
boolean sync;
boolean dsync;
boolean direct;
static Flags toFlags(Set<? extends OpenOption> options) {
Flags flags = new Flags();
for (OpenOption option: options) {
if (option instanceof StandardOpenOption) {
switch ((StandardOpenOption)option) {
case READ : flags.read = true; break;
case WRITE : flags.write = true; break;
case APPEND : flags.append = true; break;
case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
case CREATE : flags.create = true; break;
case CREATE_NEW : flags.createNew = true; break;
case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
case SPARSE : /* ignore */ break;
case SYNC : flags.sync = true; break;
case DSYNC : flags.dsync = true; break;
default: throw new UnsupportedOperationException();
}
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS && O_NOFOLLOW != 0) {
flags.noFollowLinks = true;
continue;
}
if (ExtendedOptions.DIRECT.matches(option)) {
flags.direct = true;
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException(option + " not supported");
}
return flags;
}
}
As a workaround you can revert the last access time after accessing the file:
// Create a file and write some content (empty files don't have their last access time updated after accessing - at least on Windows)
Path file = Files.createTempFile(null, null);
Files.write(file, Arrays.asList("line 1", "line 2"));
// Retrieve the last access time attribute before accessing the file
FileTime lastAccessTimeBeforeAccessing = getLastAccessTime(file);
// Access the file
Files.readAllLines(file);
// Retrieve the last access time attribute after accessing the file
FileTime lastAccessTimeAfterAccessing = getLastAccessTime(file);
// Revert the last access time
Files.setAttribute(file, "basic:lastAccessTime", lastAccessTimeBeforeAccessing);
// Retrieve the last access time attribute after reverting it
FileTime lastAccessTimeAfterReverting = getLastAccessTime(file);
// at this point:
// * lastAccessTimeBeforeAccessing.equals(lastAccessTimeAfterAccessing) is false
// * lastAccessTimeBeforeAccessing.equals(lastAccessTimeAfterReverting) is true
The getLastAccessTime
function is:
private static FileTime getLastAccessTime(Path file) throws IOException {
BasicFileAttributes basicFileAttributes = Files.readAttributes(
file, BasicFileAttributes.class);
return basicFileAttributes.lastAccessTime();
}
Upvotes: 1