【问题标题】:How to check if a file is readable?如何检查文件是否可读?
【发布时间】:2012-08-07 17:44:16
【问题描述】:

我正在编写 Java 6 应用程序,我必须检查文件是否可读。但是,在 Windows 上 canRead() 总是返回 true。所以我认为,唯一的解决方案可能是一些基于 WINAPI 并用 JNA/JNI 编写的本机解决方案。

但是,还有另一个问题,因为在 WINAPI 中很难找到一个简单的函数来返回有关访问文件的信息。我找到了GetNamedSecurityInfoGetSecurityInfo,但我不是高级 WINAPI 程序员,它们对于我来说与 JNA/JNI 连接起来太复杂了。任何想法如何处理这个问题?

【问题讨论】:

  • 您可以尝试读取文件,看看是否有错误。
  • 正确性比速度更重要。 ;) 您无需阅读整个文件,只需打开并关闭即可。
  • 就磁盘操作而言,打开和关闭文件所需的工作与读取与文件关联的安全描述符所需的工作大体相同。如果性能不相似,我会感到惊讶。
  • @user389658 相反。它试图像这样预测未来,这不是“最佳实践”。

标签: java winapi java-native-interface jna


【解决方案1】:

在资源的实际使用之前很久就检查资源的可访问性(在这种情况下是文件的可读性)是完全合理的。

想象一个服务器应用程序将使用一个子组件,该子组件将在一段时间后在某些情况下读取特定文件。在服务器启动时检查文件的可读性并在不可读时发出警告可能很有用。然后有人可以在情况实际导致子组件尝试读取该文件之前解决这种情况(使文件可读,任何东西)。

当然,这种前期检查并不能替代子组件中正确的异常处理(很有可能文件在开始时可读但后来变得不可读)。

所以我认为关于预检查的问题是完全正确的。

至于检查资源的方法,尽量做与实际使用情况类似的事情。如果稍后会读取该文件,请尝试读取它!

至于 Files.isReadable(...):不能保证 Files.isReadable(...) 下的文件系统提供程序没有错误。它可以返回true,如果文件被实际读取则抛出异常。

当然,如果您正在编写文件管理器应用程序,则使用 Files.isReadable(...),但我想情况并非如此。

【讨论】:

    【解决方案2】:

    尝试使用以下代码

    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;
    }
    

    【讨论】:

    • 我不喜欢使用异常代替控制结构,但在这种情况下解决方法还不错...
    • 这里的存在性和可读性检查只是多余的开销。显然,当您尝试打开文件时,它们无论如何都会发生:重复所有这些是没有意义的。
    【解决方案3】:

    Java 7 引入了Files.isReadable 静态方法,它接受文件Path,如果文件存在且可读,则返回true,否则返回false。

    From the docs

    测试文件是否可读。此方法检查文件是否存在 并且该 Java 虚拟机具有适当的权限,可以 允许它打开文件进行阅读。根据实现,这 方法可能需要读取文件权限、访问控制列表或 其他文件属性以检查对文件的有效访问。 因此,此方法对于其他文件可能不是原子的 系统操作。

    注意这个方法的结果马上就过时了,有 不保证随后尝试打开文件进行读取会 成功(甚至它会访问同一个文件)。应该小心 在安全敏感的应用程序中使用此方法时。

    例子:

    File file = new File("/path/to/file");
    Files.isReadable(file.toPath()); // true if `/path/to/file` is readable
    

    【讨论】:

    • +1 用于明确说明答案立即无用。对于任何想要做这样的事情的人,就像所有其他“我需要在阅读之前检查我是否可以阅读文件”的答案一样,this answer is a TOCTOU bug
    • @AndrewMartin 我将使用它来帮助确保用户输入了有效的输出路径 这与检查文件是否可读是完全不同的,也是根本不同的目的(在你的情况下可写?)。您正在验证路径名。
    • @AndrewHenle 你说得对,我认为我的评论没有用,所以我删除了它。
    • @AndrewMartin 我认为这是一个非常有用的评论 - 您以一种创新的方式使用 isReadable() 来验证路径名,其中“可读”部分真的无关紧要。
    【解决方案4】:

    如果你要阅读它,你只需要知道它是否可读。因此,请在需要时尝试阅读它,如果不能,请处理它。测试任何资源可用性的最佳方法就是尝试使用它并在出现异常或错误时处理它们。不要试图预测未来。

    【讨论】:

    • 所以最好的方法不是尝试读取文件属性,而是尝试读取,如果出现异常,则文件不可读......这似乎不是最好的解决方案
    • @aleroot 这似乎不是最好的解决方案,为什么?与什么相比?
    • @aleroot 这只是毫无意义的教条,尤其是因为您显然不知道“最佳解决方案”实际上是什么:否则您不会在这里问。如果捕获异常会提供您正在寻找的状态,那就是您使用的状态。我在这里推荐的不是“解决方法”,而是正确的技术。其他任何内容都是重复和多余的,或者是不正确的,绝对是一种解决方法。
    • @aleroot 那么您的“最佳实践”替代方案是什么?你把它比作什么你为什么一直回避这个问题?当调用说 DataInputStream.readUTF()?` 或 ObjectInputStrream.readObject() 时,你有什么替代方法来捕捉说 EOFException
    • @aleroot 这遭受了我上面已经指出的所有问题:总之,时间窗口和冗余,即低效率。你还没有回答我的其他问题。似乎这些讨论总是以同样的方式进行:有事实支持的合理案例被认为仅仅是“意见”,而没有支持的对公认教条的盲目应用被视为“最佳实践”。不要在编程时尚上投入过多。当你待得久一点时,你会意识到一分钟内就会有另一个人出现,而且它们往往是相互矛盾的。
    【解决方案5】:

    您可以通过这种方式更严格地使用FilePermissionAccessController

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

    如果请求的访问被允许,checkPermission 会安静地返回。如果 被拒绝,则抛出 AccessControlException。

    【讨论】:

    • 这与安全性或操作系统环境有关吗?如果它与后者相关,那就太好了。
    • 总是意味着 = 用于可读和不可读的文件。有人遇到同样的问题:stackoverflow.com/questions/11739183/…
    • 这不会检查文件是否可读。它检查当前执行的 Java 代码是否有一个 .policy 文件条目,允许 Java 安全管理器授予尝试读取文件的权限:如果没有安装安全管理器,它将始终成功,这里很可能就是这种情况。操作系统是否允许开放是完全不同的事情。没有答案。
    猜你喜欢
    • 1970-01-01
    • 2011-02-28
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多