9

I'm writing Java 6 application and I have to check if a file is readable. However, on Windows canRead() always returns true. So I see that probably, the only solution could be some native solution based on WINAPI and written in JNA/JNI.

But, there is another problem, because it's difficult to find a simple function in WINAPI which would return information about access to a file. I found GetNamedSecurityInfo or GetSecurityInfo but I'm not an advanced WINAPI programmer and they are too complicated for me in connection with JNA/JNI. Any ideas how to deal with this problem?

Roman C
  • 49,761
  • 33
  • 66
  • 176
peter
  • 631
  • 2
  • 7
  • 18
  • 10
    You could try reading the file and see if you get an error. – Peter Lawrey Aug 10 '12 at 12:12
  • 4
    Related: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6203387 – adarshr Aug 10 '12 at 12:14
  • @Peter Lawrey I'm afraid it's a slow solution and not a best practice. – peter Aug 10 '12 at 12:15
  • 2
    Correctness is more important than speed. ;) You don't need to read the entire file, just open it and close it. – Peter Lawrey Aug 10 '12 at 12:27
  • 4
    In terms of disk operations, the work required to open and close a file is much the same as the work required to read the security descriptor associated with the file. I'd be surprised if the performance wasn't similar. – arx Aug 10 '12 at 13:11
  • 1
    @user389658 On the contrary. It is trying to predict the future like this that is not 'best practice'. – user207421 Aug 11 '12 at 03:20
  • @EJP so the 'best practice' for you is using and exception instead of a control structure ? Good ! :-) – aleroot Aug 11 '12 at 07:10
  • 1
    If you're trying to read the file anyway, the exception is a good route. If you're trying to *display* the readability of the file, then the exception does not as adequately represent your desired operation. Context is king. – technomage Aug 11 '12 at 10:06
  • 1
    @aleroot There is no 'instead of a control structure' about it. You must use the exception to avoid all the issues named in my answer. There's no choice, and the dichotomy you have presented between exceptions and control structures is entirely false. Your concept of 'best practice' is deeply flawed. – user207421 Nov 27 '14 at 02:24
  • Checking for readability and then actually trying to read the file not only adds extraneous overhead, it [also introduces a TOCTOU bug](https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use). In general, "Do X to see if I can do Y before I do Y" is a bad idea - X doesn't exactly duplicate what Y does, and conditions can change between X and Y. If you have to do Y, **just do Y - and handle errors properly**. Because you have to handle errors from Y properly anyway. – Andrew Henle Feb 18 '18 at 13:41

5 Answers5

11

Java 7 introduced the Files.isReadable static method, it accepts a file Path and returns true if file exists and is readable, otherwise false.

From the docs

Tests whether a file is readable. This method checks that a file exists and that this Java virtual machine has appropriate privileges that would allow it open the file for reading. Depending on the implementation, this method may require to read file permissions, access control lists, or other file attributes in order to check the effective access to the file. Consequently, this method may not be atomic with respect to other file system operations.

Note that the result of this method is immediately outdated, there is no guarantee that a subsequent attempt to open the file for reading will succeed (or even that it will access the same file). Care should be taken when using this method in security sensitive applications.

Example:

File file = new File("/path/to/file");
Files.isReadable(file.toPath()); // true if `/path/to/file` is readable
svarog
  • 9,477
  • 4
  • 61
  • 77
  • 3
    +1 for clearly stating the answer is immediately useless. For anyone who want to do something like this, like all the other "I need to check if I can read the file before I read it" answers, [this answer is a TOCTOU bug](https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use). – Andrew Henle Feb 18 '18 at 13:48
  • @AndrewMartin *I'm going to use this to help ensure the user entered a valid output path* That's different and a fundamentally different purpose than checking to see if the file is readable (writable in your case?). You're validating a pathname. – Andrew Henle Jul 01 '18 at 15:07
  • @AndrewHenle You're right, I don't see my comment as useful so I've deleted it. – vowel-house-might Jul 03 '18 at 12:33
  • @AndrewMartin I thought it was a very useful comment - you were using `isReadable()` in an innovative way to validate a path name, where the "readable" part was really irrelevant. – Andrew Henle Jul 03 '18 at 14:08
8

Try to use the following code

public boolean checkFileCanRead(File file){
    try {
        FileReader fileReader = new FileReader(file.getAbsolutePath());
        fileReader.read();
        fileReader.close();
    } catch (Exception e) {
        LOGGER.debug("Exception when checking if file could be read with message:"+e.getMessage(), e);
        return false;
    }
    return true;
}
Jolta
  • 2,620
  • 1
  • 29
  • 42
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • I don't like use exception in place of control structure, but not bad the workaround in this case ... – aleroot Aug 10 '12 at 13:13
  • 7
    The existence and readability check here are just redundant overheads. Obviously they have to happen anyway when you try to open the file: there is no point in doing all that twice. – user207421 Aug 11 '12 at 03:14
6

You could use FilePermission and AccessController tougher in this way :

FilePermission fp = new FilePermission("file.txt", "read");
AccessController.checkPermission(fp);

If a requested access is allowed, checkPermission returns quietly. If denied, an AccessControlException is thrown.

aleroot
  • 71,077
  • 30
  • 176
  • 213
  • 1
    Is that relative to Security or to the OS environment ? If it's relevant to the latter then that's pretty neat. – James P. Aug 10 '12 at 12:53
  • Always means = for readable and not readable files. Someone had the same problem: http://stackoverflow.com/questions/11739183/accesscontroller-checkpermission-always-throws-exception – peter Aug 10 '12 at 13:03
  • 9
    This does not check whether a file is readable. It checks whether the currently executing Java code is has a .policy file entry that allows the Java Security Manager to grant permission to *attempt* to read the file: it will always succeed if there is no Security Manager installed, which may well be the case here. Whether the operation system will permit the open is a completely separate matter. Not an answer. – user207421 Aug 11 '12 at 03:14
4

You only need to know if it's readable if you are going to read it. So, just try to read it, when you need to, and deal with it if you can't. The best way to test the availability of any resource is just to try to use it and deal with the exceptions or errors as they arise. Don't try to predict the future.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • So the best way is not try to read the file attribute, is try to read and if you get an exception the file is not readable ... It doesn't seem the best solution – aleroot Aug 11 '12 at 06:40
  • @aleroot It doesn't seem the best solution why? Compared to what? – user207421 Aug 11 '12 at 12:43
  • Rely on exception instead of using control flow is never the best solution, could be a viable workaround but far away from the best solution ... – aleroot Aug 11 '12 at 13:34
  • 1
    @aleroot That's just meaningless dogma, especially as you clearly have no idea what the 'best solution' actually is: otherwise you wouldn't be asking here. If catching an exception delivers the state you are looking for, that's what you use. What I have recommended here is not a 'workaround', it is the correct technique. Anything else is repetitive and redundant, or else incorrect, and *definitely* a workaround. – user207421 Aug 12 '12 at 08:03
  • I'm not asking anything here, and i'm not willing to rely on exceptions when a normal control flow statement can be used in place ... If you think that is good rely on exception it is your opinion ... – aleroot Aug 12 '12 at 08:07
  • 1
    @aleroot So what's your 'best practice' alternative? What are you comparing it *to?* Why do you keep evading that question? And what's your alternative to catching say `EOFException` when calling say DataInputStream.readUTF()?` or `ObjectInputStrream.readObject()`? – user207421 Aug 12 '12 at 08:10
  • The best solution for me is what pointed out by the OP : if the file exist, read the attribute of the file, if it have read attribute go reading the file and in the case something goes wrong catch the exception ... – aleroot Aug 12 '12 at 08:15
  • 2
    @aleroot That suffers from all the problems I have already pointed out above: in summary, timing windows and redundancy, i.e. inefficiency. And you haven't answered my other questions. It seems that these discussions always gio the same way: a reasoned case supported by facts is dismissed as mere 'opinion', while an unsupported mindless application of a received dogma is presented as 'best practice'. Don't invest too heavily in programming fashions. When you've been around a bit longer you'll realize that there will be another one along in a minute, and often they are mutually inconsistent. – user207421 Aug 13 '12 at 03:53
1

It can be perfectly reasonable to check accessibility of a resource (readability of a file in this case) long before the actual usage of that resource.

Imagine a server application which will use a subcomponent which will read a particular file in some circumstances some time later. It can be useful to check the readability of the file at server startup and WARN if it's not readable. Then somebody can fix the situation (make the file readable, anything) before the circumstances actually causes the subcomponent to try to read that file.

Of course, this upfront check is not a substitute for proper exception handling in the sub component (it's very possible that the file is readable at start but became unreadable later).

So the question about pre-checking is perfectly valid I think.

As for the method of checking the resource, try to do something as similar as possible to actual usage. If later the file will be read, then try to read it!

As for Files.isReadable(...): there's no guarantee that the file system provider beneath Files.isReadable(...) is not buggy. It can return true, and then throw an exception if the file is actually read.

Of course, if you are writing a file manager application then use Files.isReadable(...), but I guess that is not the case.

riskop
  • 1,693
  • 1
  • 16
  • 34