Java中的资源,URI,URL,路径和文件有什么区别?

Chr*_*ian 88 java url terminology

我现在正在查看一段Java代码,它将路径作为String并使用其获取URL URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);,然后调用String path = resource.getPath()并最终执行new File(path);.

哦,还有电话URL url = resource.toURI();String file = resource.getFile().

我现在完全糊涂了 - 主要是因为术语,我猜.有人可以带我解决这些差异,或提供一些防伪材料的链接吗?特别是URI到URL和资源到文件?对我来说,感觉它们应该是相同的东西,分别......

之间的差异getFile(),并getPath()在此说明:有什么url.getFile()和的getPath()有什么区别?(有趣的是他们似乎都回归了Strings,这可能会增加我的心态...)

现在,如果我有一个引用jar文件中的类或包的定位器,那两个(即路径文件串)是否会有所不同?

resource.toString()jar:file:/C:/path/to/my.jar!/com/example/毕竟会给你(注意感叹号).

Java中的URIURL 之间的区别是前者不编码空格吗?参看 Java中存在冲突的文件,URI和URL(这个答案很好地解释了这两个术语之间的一般概念差异:URI识别和URL定位;)

最后 - 最重要的是 - 为什么我需要File对象; 为什么资源(URL)不足够?(还有一个Resource对象吗?)

对不起,如果这个问题有点无组织; 它只是反映了我的困惑...... :)

Pav*_*ral 42

更新2017-04-12检查JvR的答案,因为它包含更详尽和准确的解释!


请注意,我不认为自己100%有能力回答,但不过这里有一些评论:

  • File 表示可通过文件系统访问的文件或目录
  • resource是数据对象的通用术语,可以由应用程序加载
    • 通常资源是随应用程序/库一起分发的文件,并通过类加载机制加载(当它们驻留在类路径上时)
  • URL#getPath是URL(protocol://host/path?query)的路径部分的getter
  • URL#getFile 根据JavaDoc返回 path+query

在Java中,URI它只是用于操纵通用标识符本身的数据结构.

URL另一方面,它实际上是一个资源定位器,并为您提供通过注册URLStreamHandlers 实际读取资源的功能.

URL可以导致文件系统资源,您可以使用file://协议(因此File< - > URL关系)为每个文件系统资源构建URL .

还要注意那URL#getFile与之无关java.io.File.


为什么我需要File对象; 为什么资源(URL)不够?

这就够了.只有当您想将资源传递给某些只能处理文件的组件时,您才需要从中获取File.但是,并非所有资源URL都可以转换为Files.

是否有资源对象?

从JRE的角度来看,这只是一个术语.一些框架为您提供了这样的类(例如Spring的资源).

  • 还有`java.nio.file.Path`,它基本上是`java.io.File`的(Java 7+)替代品,因为后者的API在Java的早期显然很少被人们考虑过. (5认同)
  • @kibibyte:我希望调用是阻塞的,有一个hashcode和equals的异步实现,现在非常令人不安.我认为你的意思是调用将尝试解析主机以查找它们是否相同,从而可能阻止网络调用. (3认同)

小智 42

我现在完全糊涂了 - 主要是因为术语,我猜.有人可以带我解决这些差异,或提供一些防伪材料的链接吗?特别是URI到URL和资源到文件?对我来说,感觉它们应该是相同的东西,分别......

该术语令人困惑,有时甚至令人困惑,并且主要源于Java作为API和随时间推移的平台的演变.要理解这些术语如何表达它们的作用,重要的是要认识到影响Java设计的两件事:

  • 向后兼容性. 旧应用程序应在较新的安装上运行,理想情况下无需修改.这意味着需要通过所有较新版本维护旧的API(及其名称和术语).
  • 跨平台. API应提供其底层平台的可用抽象,无论是操作系统还是浏览器.

我将介绍这些概念以及它们是如何形成的.之后我会回答你的其他具体问题,因为我可能需要在第一部分中提到一些内容.

什么是"资源"?

可以定位和读取的抽象通用数据. 松散地说,Java使用它来引用一个"文件",它可能不是一个文件,但确实代表一个命名的数据. 它在Java中没有直接的类或接口表示,但由于其属性(可定位,可读),它通常由URL表示.

因为Java的早期设计目标之一是在浏览器中运行,作为具有非常有限的权限/特权/安全许可的沙盒应用程序(applets!),Java在文件之间产生明显的(理论上的)差异(在本地的某些东西)文件系统)和资源(需要阅读的东西). 这就是为什么读取与应用程序相关的内容(图标,类文件等)是ClassLoader.getResource通过File类完成的,而不是通过File类完成的.

不幸的是,因为"资源" 这种解释之外也是一个有用的通用术语,它也用于命名非常具体的东西(例如,类ResourceBundle,UIResource,Resource),在这个意义上它们不是资源.

表示资源(路径)的主要类是java.nio.file.Path,java.io.File,java.net.URIjava.net.URL.

文件(java.io,1.0)

文件和目录路径名的抽象表示.

File类表示可通过平台的本机文件系统访问的资源.它只包含文件的名称,所以它实际上是主机平台根据自己的设置,规则和语法解释的路径(见后文).

请注意,File不需要指向本地的东西,只是主机平台在文件访问的上下文中理解的东西,例如Windows中的UNC路径.如果在操作系统中将ZIP文件作为文件系统挂载,则File将正确读取其包含的条目.

URL(java.net,1.0)

类URL表示统一资源定位符,指向万维网上"资源"的指针.资源可以是文件或目录这样简单的东西,也可以是对更复杂的对象的引用,例如对数据库或搜索引擎的查询.

与资源的概念一起,URL表示该资源的方式与File类表示主机平台中的文件的方式相同:作为指向资源的结构化字符串. URL另外包含一个提示如何到达资源的方案("file:"是"询问主机平台"),因此允许通过HTTP,FTP,JAR内部以及诸如此类的东西指向资源.

不幸的是,URL带有自己的语法和术语,包括使用"文件"和"路径".如果URL是文件URL,则URL.getFile将返回与引用文件的路径字符串相同的字符串.

Class.getResource 返回一个URL:它比返回File更灵活,它满足了1990年代早期想象的系统需求.

URI(java.net,1.4)

表示统一资源标识符(URI)引用.

URI是URL的(轻微)抽象. URI和URL之间的区别是概念性的,主要是学术性的,但URI在形式上更好地定义,并涵盖更广泛的用例.因为URL和URI不是同一个东西,所以引入了一个新类来表示它们,方法URI.toURL和URL.toURI在一个和另一个之间移动.

在Java中,URL和URI之间的主要区别在于URL 具有可解析的期望,应用程序可能需要InputStream; 一个URI更像是一个抽象的东西,它可能指向可解析的东西(通常也是如此),但它意味着什么以及如何达到它对上下文和解释更加开放.

路径(java.nio.file,1.7)

可用于在文件系统中查找文件的对象.它通常表示系统相关的文件路径.

在Path接口中图标化的新文件API允许比File类提供的更大的灵活性.Path接口是File类抽象,是New IO File API的一部分.File必须指向主机平台所理解的"文件",Path更通用:它表示任意文件系统中的文件(资源).

Path消除了对主机平台文件概念的依赖.它可以是ZIP文件中的条目,可通过FTP或SSH-FS访问的文件,应用程序类路径的多根表示,或者可以通过FileSystem接口及其驱动程序FileSystemProvider进行有意义表示的任何内容.它将"挂载"文件系统的强大功能带入Java应用程序的上下文中.

主机平台通过"默认文件系统"表示; 当你打电话时File.toPath,你会在默认文件系统上获得一个Path.


现在,如果我有一个引用jar文件中的类或包的定位器,那两个(即路径文件串)是否会有所不同?

不太可能.如果jar文件是本地文件系统上,你不应该有一个查询组件,所以URL.getPathURL.getFile应该返回相同的结果.但是,选择你需要的那个:文件URL通常不具有查询组件,但我总是可以添加一个.

最后 - 最重要的是 - 为什么我需要File对象; 为什么资源(URL)不够?

URL可能不够,因为File允许您访问内务处理数据,例如权限(可读,可写,可执行),文件类型(我是目录吗?),以及搜索和操作本地文件系统的能力.如果这些是您需要的功能,则文件或路径会提供它们.

如果您有权访问Path,则不需要File.但是,一些较旧的API可能需要File.

(还有一个Resource对象吗?)

不,没有.有许多名称喜欢它,但它们不是一种意义上的资源ClassLoader.getResource.


leo*_*loy 11

Pavel Horal的回答很好.

正如他所说,"文件"一词在URL#getFilevs中 具有完全不同(几乎无关)的含义java.io.File- 可能是混淆的一部分.

只是添加:

  • 一个 资源在Java是一个抽象的概念,数据源可以读取.资源的位置(或地址)由Java在URL对象中表示.

  • 一个 资源可以对应于一个普通文件在本地文件系统(具体而言,当其URL开始file://).但是资源更通用(它也可以是存储在jar中的某个文件,或者是从网络或内存中读取的某些数据,或者......).而且它也更受限制,因为File除了常规文件以外的其他东西:目录,链接也可以创建和写入.

  • 请记住,在Java中,File对象并不真正表示"文件",而是表示文件的位置(全名,带路径).因此,File对象允许您定位(和打开)文件,因为URL允许您访问(和打开)资源.(ResourceJava中没有类来表示资源,但是没有一个表示文件!再一次:File不是文件,它是文件的路径).