是否可能存在一个(Java 7)文件系统,其中路径 .isAbsolute() 为 true,但根路径为 null?

35

.isAbsolute()的javadoc说:

告诉我们这个路径是否是绝对路径。
绝对路径是完整的,不需要与其他路径信息结合就能定位到文件。

返回值: true 如果且仅如果这个路径是绝对路径

.getRoot()的javadoc说:

返回此路径的根组件作为Path对象,如果此路径没有根组件,则返回null。

返回值: 表示此路径的根组件的路径,或者null

好的,我有点迷茫了;是否存在某些文件系统,其路径可能是绝对路径但没有根?


编辑:请注意,可能存在具有根目录但不是绝对路径的路径。例如,在Windows系统上:

  • C:foo;
  • \foo\bar

但我在这里要求的是反过来:没有根目录且是绝对路径。


我不知道有哪个真实的文件系统具有这样的行为,但是FileSystem是一个public abstract class。你可能想要扩展它(以及它返回的Path实例)来实现某些功能。 - Sotirios Delimanolis
@SotiriosDelimanolis 我知道这一切,我正在开发一个 FileSystem 辅助库并探索 API 的方方面面 ;) - fge
2
你要进入兔子洞了。 - Sotirios Delimanolis
很抱歉,我可能误解了什么,但是你怎么可能没有根目录而拥有绝对路径呢? - Rudi Kershaw
1
@Rudi 这正是我所问的;java.nio.file的javadoc没有提到这是不可能的。他们一定有理由这样做,对吧?还是只是为了满足Windows和它“损坏”的文件系统模型? - fge
5
@fge 在这里提到:https://docs.oracle.com/javase/tutorial/essential/io/path.html#relative 绝对路径总是包含根元素。所以至少在那里他们提到了。 - dfherr
3个回答

16

嗯,文件系统中有一些模糊的东西。我制作了一些企业搜索爬虫,在使用路径时会注意到一些奇怪的文件系统问题。顺便说一句:这些都是自定义(覆盖)的文件系统实现,没有标准的文件系统,你肯定可以争论这些东西哪些是好主意,哪些不是... 不过,我认为在标准文件系统中不会遇到这些情况。

下面是一些奇怪的例子:

容器文件系统中的文件(OLE2、ZIP、TAR 等):c:\foo\bar\blah.zip\myfile

在这种情况下,你可以决定哪个项目是“根”:

  • 'c:\' ? 那不是包含文件的 zip 文件的根目录...
  • 'c:\foo\bar\blah.zip' ? 这可能是文件的根目录,但这样做可能会破坏你的应用程序。
  • 'blah.zip' ? 可能是 zip 文件的根目录 - 但不管怎样,这也可能会破坏你的应用程序。
  • '/' ? 就像在 zip 文件中的“/”文件夹一样?这可能是可能的,但长期来看这将给你带来严重的头痛。

类似于 HTTP 的“图形”结构:

  • 事实上你有'/foo/bar'并不意味着 '/foo' 甚至 '/' 存在。(假设那符合你的标准)。唯一能做的就是遍历这个图...
  • 请注意,像 WebDav 这样的协议是基于 HTTP 的,可能会给你带来类似的头痛。我这里有一些自定义 webdav 文件系统的例子,它们没有“根”文件夹,但具有绝对路径。

尽管如此,你可以争论最高常见路径(如果存在...)可以到达根,还是存在根 - 但你简单地无法到达它(即使它真的不存在)。

Samba/netbios

如果您将完整的Samba(Windows网络)网络视为单个文件系统,则基本上会得到一个包含所有工作组的“根”,一个包含所有计算机的工作组,一个包含所有共享的计算机,以及共享中的文件。

然而...根和工作组并不存在。它们是由广播协议组成的东西(如果您拥有超过1000台计算机的网络,则广播协议也非常不可靠)。从爬虫的角度来看,将“根”和“工作组”目录与(可靠的)其他目录完全区分开来是很有意义的。

然而

这些情况仅描述了根目录无法访问、不可靠或其他情况下的路径。理论上,我认为在您可以想到的任何URL中,都始终存在一个根目录。毕竟,它是由定义层次结构的字符字符串组成的,因此根据定义具有起始点。


嗯,既然我正在使用这个API开发自定义文件系统,所以我很感兴趣...你的论点很有道理。我已经完成了三个:Dropbox、box.com和FTP。但是这些都不太适用,可以这么说。 - fge
@fge 是的,我之前也这样做了一段时间,包括其他几十种协议和文件格式。基本上你有分层文件系统 - 几乎所有的都可以工作并符合标准 - 和图形文件系统 - 所有这些都将在此方面失败(例如社交媒体图形、http等)。分层文件系统要么是顺序的(例如tar.bz2),要么是随机访问的(例如OLE2、ZIP、您的C驱动器、dropbox等)。哦,显然还有组合。以此为设计思路,你就会没问题。 - atlaste

14

语义问题

从我的理解来看,只有可以追溯到根目录的路径才能被称为绝对路径。因此,不应该出现没有根的绝对路径。尽管我们可以找到定义绝对路径的定义(例如下面的例子);

在这一点上唯一真正的问题是Java API的定义是否与上述定义相符。我唯一能够找到有关绝对路径定义(涉及根元素)的官方Oracle来源是在官方Java教程中。官方Java教程中写道:

绝对路径始终包含根元素

如果相信这个声明,那么没有任何文件系统(无论多么模糊)可以包含Java API将认为是绝对的Path,除非它也认为它包含根

你可以认为在某些非层次文件系统中,您可能会遇到一些问题,无法确定文件是否可以成为其自身的根。但是,根据这个定义,在Path API中,路径不应表示非分层元素;

Path表示一个分层级结构并由一系列目录和文件名元素组成


@fge - 你可以轻松地从语义上理解这个问题,因为绝对路径的定义各不相同,但我认为根本问题(没有双关语)是,如果Java API中的路径不包含根目录,它是否仍然被视为绝对路径。在这种情况下,我们只能信任Oracle的源代码,答案是否定的(即使在教程中提到得非常牵强)。 - Rudi Kershaw
@Rudi:所以你依赖于每个编写合理文件系统的人都阅读了教程并遵循了它的事实。教程不是合同。在库中依赖这一点感觉相当脆弱。 - gexicide
@gexicide - 是的,但是如果一个自定义操作系统运行一个自定义文件系统并且要运行JVM,它将不得不使用一个具有预定绝对定义的现有JVM,如果我说错了,请纠正我。 - Rudi Kershaw

12

定义

接口对于根目录的定义如下:

可能还存在一个标识文件系统层次结构的根组件。

因此,你可以看到,这个注释似乎意味着根目录用于文件系统层次结构。现在我们要理解什么是绝对路径。接口告诉我们以下内容:

绝对路径是完整的,它不需要与其他路径信息组合以定位文件。

所以,你可以看到,在关于绝对路径的定义中没有任何关于根目录的提及。唯一的限制是我们必须能够在没有进一步信息的情况下定位文件。

分层文件系统

大多数文件系统都是分层的,即它们是树状结构(如果考虑链接,则为图形)或森林。树中的根是一个未被另一个节点包含的节点(排除链接)。例如,Windows文件系统是森林,因为它们有许多根目录(C:D:等等)。Linux通常只有一个根目录,即/。根目录非常重要,因为如果没有它,就很难开始定位文件。在这样的文件系统中,你通常可以依赖每个绝对路径都有一个根。

非分层文件系统

只要我们拥有分层文件系统,就可以预期绝对路径中会有一个根目录,但是如果没有呢?那么,绝对路径可能不包含根。

我能想到的一个例子是:像Chord这样的分布式文件系统,它们通常不是分层的,因此根目录的意义通常是未定义的。相反,文件哈希标识了一个文件(在Chord中为SHA-1),因此有效的Chord路径可能看起来像这样:

cf23df2207d99a74fbe169e3eba035e633b65d94

这是一个绝对路径。由于路径是绝对的,因此可以在不需要其他信息的情况下检索相关文件。然而,我没有看到根目录。我们可以定义整个哈希为其自己的根(然后每个文件将成为其自己的根),但是没有人能保证实现Chord文件系统的每个人都同意这一点。因此,可能有合理的实现不将这些哈希视为根。在这样的文件系统中,每个路径都是绝对的,但没有一个包含根目录。

如果我要实现非层次结构的文件系统,我将始终返回null作为空根,因为在我看来,在非层次结构的文件系统中根本就不存在定义明确的概念。既然我这样想,其他开发者也可能这样想。因此,您不能假设每个绝对路径都有一个根。

请注意,分布式文件系统在许多领域都很常见,因此这不仅仅是一个永远不会实现的边角案例。我认为你必须预见到这一点。

结论

  1. 接口并不要求每个绝对路径必须有根
  2. 有合理的文件系统没有根是有意义的
  3. 评论中提到的Oracle教程不是接口的合同。您不应该依赖它

因此,将有人实现没有根的文件系统;你应该预见到这一点。


很好的捕捉哈希路径 :) 真的很有趣,我完全同意一个只有绝对路径的文件系统可以被认为没有根。 - dfherr
无论我们或文件系统如何定义它,都不重要。难道不是JVM的定义最重要吗? - Rudi Kershaw
@Rudi:重要的是接口合同中所写的内容(即类的javadoc)。目前,其中的信息不足。如果Oracle想强制执行此规定,则需要修补javadoc。但那时为时已晚,许多不符合规范的实现已经存在。 - gexicide
毫无异议。 - Rudi Kershaw
1
@gexicide 我考虑过分布式系统,但基本上我在我的实现中所做的是,如果你有 foo://[hashcode or id],你可以调用 foo:// 作为根节点,并简单地指出它不可访问,在这种情况下,客户端 仍然会认为存在根节点,尽管分布式系统/服务器认为它不存在。这与 http://foo/bar 中的 http://foo/ 不存在是相同的。你甚至可以说 http 在这种情况下是根 - 但这与 Java 接口相反... 最终它将归结为“存在”的定义。 - atlaste
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接