【问题标题】:Files.exists(path) and path.toFile().exists() give different results for the same fileFiles.exists(path) 和 path.toFile().exists() 对同一个文件给出不同的结果
【发布时间】:2016-01-29 15:08:26
【问题描述】:

对于 Windows 上的本地文件,Files.exists(path)path.toFile().exists() 的结果不同。我可以在 Windows 资源管理器中看到这个文件,尽管我(随机)修改了权限,而且权限可能没有意义。

但这并不能解释为什么旧方法返回 true 而新方法返回 false。该文件确实存在,但运行 Java 代码的用户可能看不到它,所以我不确定正确的答案应该是什么。我也看不到如何查看哪个用户正在运行代码,计算机上只有一个真实用户 Paul,但我想知道是否以管理员身份运行是否会影响事情。

System.out.println("Path Exists(1):"+Files.exists(path));
System.out.println("Path Exist(2) :"+path.toFile().exists());

给予

Path Exists(1):false
Path Exist(2) :true

还有

System.out.println("Path readable(3) :"+Files.isReadable(path));
System.out.println("Path readable(4):"+path.toFile().canRead());

以同样的方式给予

Path readable(3) :false
Path readable(4):true

权限输出

File C:\Code\jthink\opensrc\jaudiotagger\testdata\test157.dsf permissions
owner:PCLAPTOP\Paul
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:DENY
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:DENY
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
BUILTIN\Users:READ_DATA/READ_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/READ_ACL/SYNCHRONIZE:ALLOW
NT AUTHORITY\Authenticated Users:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/SYNCHRONIZE:ALLOW


c:\Code\jthink\opensrc\jaudiotagger>attrib C:\Code\jthink\opensrc\jaudiotagger\testdata\test157.dsf
A    R       C:\Code\jthink\opensrc\jaudiotagger\testdata\test157.dsf

更新 我没有结论,但认为这些信息可能有用。

我在 IntelliJ IDE 中运行代码,但未启用 IDE 以管理员身份运行程序选项,启用此选项后,Java 应用程序也获得了管理员权限。

对另一个文件很感兴趣,我没有添加任何 DENY 权限,我只是禁用了继承权限并从所有组中删除了 READ 权限。然后,当我以用户身份运行而没有启用以管理员身份运行时,它无法读取文件,而且这段代码也无法输出任何信息

AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class);
if (view != null)
{
    sb.append("Owner:"+view.getOwner().getName()+"**");
    for (AclEntry acl : view.getAcl())
    {
        sb.append(acl.principal()+"**");
        for(AclEntryPermission aep:acl.permissions())
        {
            sb.append(aep.toString() + "**");
        }
    }
}

但是当我启用 Run program as adminstrator 运行时,它仍然无法读取文件,但上面的代码现在确实输出了一些权限,如下所示:

所有者:BUILTIN\Administrators

NT AUTHORITY\SYSTEM:WRITE_DATA/APPEND_DATA/WRITE_NAMED_ATTRS/WRITE_ATTRIBUTES/SYNCHRONIZE:ALLOW PCLAPTOP\Paul:WRITE_DATA/APPEND_DATA/WRITE_NAMED_ATTRS/WRITE_ATTRIBUTES/SYNCHRONIZE:ALLOW BUILTIN\Administrators:WRITE_DATA/APPEND_DATA/WRITE_NAMED_ATTRS/WRITE_ATTRIBUTES/SYNCHRONIZE:ALLOW

如您所见,即使 Administrators 没有 READREAD PERMISSIONS 选项,它们也可以输出权限,而之前不能,可能是由于 BUILTIN/Administraor 作为所有者返回。

【问题讨论】:

  • 这是一个音频文件。
  • 你如何构建path
  • 我已将输出添加到问题
  • 您能说明如何初始化您的path 变量吗?
  • 第一个问题呢? ("你是如何构建路径的?")

标签: java security nio


【解决方案1】:

尝试阅读以下内容: https://docs.oracle.com/javase/tutorial/essential/io/check.html

它指出,Files.exists(path) 返回 false 并不意味着它不存在,所以是的,它似乎存在权限问题。试试Files.notExists(path) 看看它会返回什么。如果为false,则表示无法判断文件是否存在,如果返回true,可能是你的代码有问题。

尝试从命令行而不是 netbeans 运行您的文件。如果你不知道怎么做,你可以搜索谷歌,这上面有很多东西,但基本上你想做的是用javac myfile.java编译.java文件,然后用java myfile运行它.使用普通命令提示符执行此操作,并以管理员身份打开并查看您得到的结果。

【讨论】:

  • 当我读到这篇文章时,我认为这意味着它由于网络问题而无法访问,但是是的,我认为你是对的。但我不认为这是对旧方法的改进。我曾经检查文件是否存在,然后检查文件的可读性,现在看来,如果我有文件读取权限,我只能检查文件是否存在。我知道如何从命令行运行,但是您如何在 Windows 上以管理员身份从命令行运行。
  • 据我所知,以管理员身份启动命令行就足够了。我不确定我理解你所说的改进是什么意思。我认为您的方法很好,它遵循文档并检查是否存在和可读性。正如亚历克斯所说,问题似乎是您的访问权限,如果您在某种网络服务器(JBoss,Tomcat)上运行它,请尝试检查它们的设置。
  • 通过'改进'我的意思是使用旧的 file.exists() 方法,您可以检查文件是否存在而不管您的权限如何,然后您可以使用 canRead(0 来检查您是否可以读取它。使用新的 exists() 方法,如果您有权限,您似乎只能检查它是否存在,因此您无法区分不存在和存在,但无权检查是否存在。感谢找到命令提示符(管理员)现在选择,但我仍然想知道如何运行选择是否以 JetBrains 的管理员身份运行。
  • 嗯,好的。我认为其中一个没有任何改进,它们只是有不同的用例。毕竟 path.toFile().exists() 也可以为在某些情况下您可能需要或可能不想要的文件夹返回 true。您是否尝试过以管理员身份启动 intellij ?这应该给子进程(运行 main 方法)相同的权限。检查这个:stackoverflow.com/questions/7736536/… 否则你可能需要设置一个配置文件或注册表,该程序应该以管理员身份运行或关闭 UAC(不推荐)
  • 我认为大多数开发人员会看到有一个新的 exists() 方法,并在旧的方法上使用它,因为从 Javadoc 中并不清楚它们有何不同。
【解决方案2】:

这些是两种不同的方法:Files.exists() 和 path.toFile().exists()。

Files.exists() 定义此抽象路径名表示的文件存在。换句话说,该文件存在并且用户可以读取它。

path.toFile().exists() 表示文件存在,则不能保证子序列访问会成功。换句话说,文件存在而不检查用户是否具有读取权限。

这真的取决于运行程序的用户。当您使用您的 ID (Paul) 工作时,它可以正常工作。尤其是在命令行中,您可以使用 ATTRIB 命令。

但是,当您使用其他应用程序来运行您的代码时,这取决于系统配置。在您的应用程序中运行此 ATTRIB 或类似命令,您将看到。

我认为您在 IIS 下运行一些网站。这种方式通常是为系统中几乎没有权限的最低级别用户配置的,以防止安全漏洞。通常是所有人或 NT AUTHORITY。如我所见,此特定访问权限无权读取您的文件

NT AUTHORITY\SYSTEM:READ_DATA/...:DENY

当然,您有 2 个不同的答案 - FALSE:运行应用程序所使用的 ID 的用户无法读取此文件,TRUE:文件实际存在。

更改您的应用程序的运行 ID 或授予每个人对该特定文件的读取权限,包括其路径中的所有目录,您将在这两种检查不同含义的方法中得到相同的结果。

【讨论】:

  • 谢谢我希望你是对的,但我没有从阅读 Javadoc 中得到它,两者都说如果存在安全管理器,他们会检查其 SecurityManager.checkRead(java.lang.String) 文件方法访问,实际上并不清楚一个忽略读取访问而另一个不忽略。(顺便说一句,您的 Javadoc 链接是错误的)。我没有运行网站,它是一个 Swing java 应用程序。我不明白如果我以管理员身份运行,除了管理员权限之外,我还没有普通用户的权限。
  • 在您的应用程序中运行命令 (Runtime.exec) 以确定您是谁 (whoami) 并查看用于运行您的应用程序的用户。这是我能看到的唯一可能的解释。 (顺便说一句,我的链接是正确的,文件是文件,文件是文件)
  • 从不知道 whoami 在 Windows 上可用 - 谢谢。但是我知道用户我不知道是否知道应用程序是否“以管理员身份运行”,即具有额外的管理员权限,因此是可能的。我再次检查了您的 Javadoc 链接,但它们似乎仍然是错误的。
猜你喜欢
  • 1970-01-01
  • 2014-12-20
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多