Java中的资源、URI、URL、路径和文件有啥区别?
Posted
技术标签:
【中文标题】Java中的资源、URI、URL、路径和文件有啥区别?【英文标题】:What's the difference between a Resource, URI, URL, Path and File in Java?Java中的资源、URI、URL、路径和文件有什么区别? 【发布时间】:2015-03-06 20:50:45 【问题描述】:我现在正在查看一段 Java 代码,它将路径作为字符串并使用 URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);
获取其 URL,然后调用 String path = resource.getPath()
,最后执行 new File(path);
。
哦,还有对URL url = resource.toURI();
和String file = resource.getFile()
的调用。
我现在完全糊涂了——我猜主要是因为术语。有人可以带我了解这些差异,或者提供一些指向 Dummy-proof 材料的链接吗?尤其是 URL 的 URI 和 文件的资源?对我来说,感觉它们应该是相同的东西,分别......
getFile()
和 getPath()
之间的区别在这里解释:What's the difference between url.getFile() and getpath()?(有趣的是,它们似乎都返回字符串,这可能会增加很多我的心态……)
现在,如果我有一个引用 jar 文件中的类或包的定位器,这两个(即文件字符串的路径)会有所不同吗?
毕竟resource.toString()
会给你jar:file:/C:/path/to/my.jar!/com/example/
(注意感叹号)。
URI 和 URL in Java 的区别是前者不编码空格吗?参照。 Files, URIs, and URLs conflicting in Java(这个答案很好地解释了这两个术语之间的一般概念区别:URIs identify and URLs locate;)
最后 - 也是最重要的 - 为什么我需要File
对象;为什么 Resource (URL
) 不够?(还有 Resource 对象吗?)
对不起,如果这个问题有点杂乱无章;它只是反映了我的困惑...... :)
【问题讨论】:
你甚至还没有开始看 NIO 的Path
和 FileSystem :)
@eckes 请一次头痛。 ;)
好吧,在您的问题的上下文中,文件/URL+URI 不相关。一种是命名和操作文件的方法,另一种是命名和读取资源(可以是文件)的方法。 getFile 和 getPath 方法处理 URL 的组件,这些组件(令人困惑地)命名为文件对象。类加载器资源不表示为文件,因为它们可以有不同的来源(或嵌套在 JAR 文件中)。
我会注意到这段代码不太可能按预期工作。 URL
是不透明的 - 如您所见,它是jar:file:
,即.jar
存档中的资源。把它改成File
不太可能产生任何有用的东西。
问题的核心在于,resource 和 path 这两个词可能有不同的含义,具体取决于上下文。
【参考方案1】:
我现在完全糊涂了——我猜主要是因为术语。有人可以带我了解这些差异,或者提供一些指向 Dummy-proof 材料的链接吗?特别是 URI 到 URL 和资源到文件?对我来说,感觉它们应该是相同的东西,分别......
该术语令人困惑,有时甚至令人困惑,并且主要源于 Java 作为 API 和平台随着时间的推移而演变。要理解这些术语的含义,重要的是要认识到影响 Java 设计的两件事:
向后兼容性。旧的应用程序应该在较新的安装上运行,最好不要修改。这意味着旧 API(及其名称和术语)需要在所有新版本中进行维护。 跨平台。 API 应提供其底层平台的可用抽象,无论是操作系统还是浏览器。我将介绍这些概念以及它们是如何形成的。在那之后我会回答你的其他具体问题,因为我可能需要在第一部分中提到一些东西。
什么是“资源”?
可以定位和读取的抽象的通用数据。简单地说,Java 使用它来指代一个“文件”,它可能不是一个文件,但确实代表一个命名的数据。 它在 Java 中没有直接的类或接口表示,但由于其属性(可定位、可读),它通常由 URL 表示。
因为 Java 的早期设计目标之一是在浏览器中运行,作为沙盒应用程序(小程序!),权限/特权/安全权限非常有限,Java 明确(理论上)区别于文件(本地文件系统上的东西)和资源(需要读取的东西)。这就是为什么读取与应用程序相关的东西(图标、类文件等)是通过ClassLoader.getResource
和不是通过 File 类。
不幸的是,因为“资源”也是一个有用的通用术语在此解释之外,它也用于命名非常具体的事物(例如类ResourceBundle、UIResource、Resource ) 从这个意义上说,它们不是资源。
表示资源(路径)的主要类是java.nio.file.Path、java.io.File、java.net.URI 和java.net.URL。
File (java.io, 1.0)
文件和目录路径名的抽象表示。
File 类表示可通过平台的本机文件系统访问的资源。它只包含文件的名称,因此它实际上更像是主机平台根据自己的设置、规则和语法解释的路径(见下文)。
请注意,File 不需要指向 本地 的东西,只需主机平台在文件访问的上下文中理解的东西,例如Windows 中的 UNC 路径。如果您将 ZIP 文件作为文件系统挂载到操作系统中,则 File 将正常读取其包含的条目。
URL (java.net, 1.0)
类 URL 代表一个统一资源定位器,一个指向万维网上“资源”的指针。资源可以是文件或目录等简单的东西,也可以是对更复杂对象的引用,例如对数据库或搜索引擎的查询。
与资源的概念相结合,URL 表示该资源的方式与 File 类表示主机平台中的文件的方式相同:作为 一个指向资源的结构化字符串。 URL 另外包含一个提示如何访问资源的方案(“文件:”是“询问主机平台”),因此允许通过 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 更像是一个抽象的 thingamajig,它可能指向可解析的东西(通常确实如此),但它的含义以及如何到达它对上下文和解释更加开放。
Path (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
时,您会在默认文件系统上获得一个路径。
现在,如果我有一个引用 jar 文件中的类或包的定位器,这两个(即文件字符串的路径)会有所不同吗?
不太可能。如果 jar 文件在本地文件系统上,则不应有查询组件,因此 URL.getPath
和 URL.getFile
应返回相同的结果。但是,请选择您需要的那个:文件 URL 通常可能没有查询组件,但我肯定会添加一个。
最后——也是最重要的——为什么我需要 File 对象;为什么资源 (URL) 不够?
URL 可能还不够,因为 File 使您可以访问诸如权限(可读、可写、可执行)、文件类型(我是目录吗?)等管理数据,以及搜索和操作本地文件系统的能力。如果这些是您需要的功能,那么 File 或 Path 会提供它们。
如果您可以访问 Path,则不需要 File。不过,一些较旧的 API 可能需要 File。
(还有资源对象吗?)
不,没有。有很多类似的东西,但它们不是ClassLoader.getResource
意义上的资源。
【讨论】:
哇,非常彻底。只是通过它,但已经有了第一个后续问题:当您说文件“仅包含文件名”时,您是否与最初的陈述相矛盾,即“文件和目录路径名的抽象表示” - iemore? @Christian 我的意思是“只有名称”,如:不以任何方式模拟文件的内容;它只是围绕字符串的薄包装。 “抽象表示”部分引用自 API 文档。 ;) 这个答案应该得到更多的支持......将更新我接受的答案,以将读者指向这个答案。【参考方案2】:2017-04-12 更新检查JvR's answer,因为它包含更详尽和准确的解释!
请注意,我不认为自己 100% 有能力回答,但这里有一些 cmets:
File
表示可通过文件系统访问的文件或目录
resource 是一个generic term 用于可以由应用程序加载的数据对象
通常资源是与应用程序/库一起分发并通过类加载机制加载的文件(当它们驻留在类路径上时)
URL#getPath
是 URL 路径部分的吸气剂 (protocol://host/path?query
)
URL#getFile
根据 JavaDoc 返回 path+query
在 Java 中,URI
只是一个用于操作通用标识符本身的数据结构。
另一方面,URL
确实是一个资源定位器,并为您提供通过注册的URLStreamHandler
s 实际读取资源的功能。
URL 可以指向文件系统资源,您可以使用 file://
协议为每个文件系统资源构造 URL(因此 File
URL
关系)。
还要注意URL#getFile
与java.io.File
无关。
为什么我需要 File 对象;为什么资源 (URL) 不够?
够了。只有当您想将资源传递给某些只能处理文件的组件时,您才需要从中获取File
。但并非所有资源 URL 都可以转换为 File
s。
还有资源对象吗?
从 JRE 的角度来看,它只是一个术语。一些框架为你提供了这样的类(例如Spring's Resource)。
【讨论】:
还有java.nio.file.Path
,它基本上是java.io.File
的(Java 7+)替代品,因为后者的 API 在 Java 的早期显然没有经过深思熟虑。
一般情况下,除非绝对需要,否则应尽量减少 URL 的使用。原因是 URL 的 equals 和 hashCode 方法以一种令人惊讶的方式实现:它们是阻塞方法调用。
@kibibyte:我希望调用是阻塞的,现在有一个异步实现的哈希码和等于,这将是非常令人不安的。我认为您的意思是调用将尝试解析主机以查找它们是否等效,因此可能会阻塞网络调用。【参考方案3】:
Pavel Horal's answer 很好。
正如他所说,“文件”这个词在 URL#getFile
和 java.io.File
中具有完全不同(实际上不相关)的含义——这可能是混淆的一部分。
只是补充:
Java 中的资源 是一个抽象概念,是可以读取的数据源。资源的位置(或地址)在 Java 中由 URL
对象表示。
资源 可以对应于本地文件系统中的常规文件(特别是当其URL
以file://
开头时)。但是资源更通用(它也可以是一些存储在 jar 中的文件,或者一些要从网络读取的数据,或者从内存中读取,或者......)。而且它也受到更多限制,因为File
(除了是常规文件之外的其他东西:目录,链接)也可以创建和写入。
请记住,在 Java 中,File
对象并不真正代表“文件”,而是文件的位置(全名,带路径)。因此,File
对象允许您定位(并打开)文件,URL
允许您访问(并打开)资源。 (Java 中没有 Resource
类来表示资源,但也没有类来表示文件!再一次:File
不是文件,它是文件的路径)。
【讨论】:
【参考方案4】:据我了解,您可以将它们分类如下:
基于 Web:URI 和 URL。
网址:网址是互联网上的一个确定位置(只是一个普通的网址,例如 - ***.com) URIs:曾经的 URL 是一个 URI。但是 URI 也可以包含诸如“mailto:”之类的东西,所以它们也是,我想说的一些“脚本”。和本地:资源、路径和文件
资源:资源是 jar 中的文件。它们用于从罐子/容器中加载文件。 路径:路径基本上是一个字符串。但它带有一些方便的函数来连接多个字符串,或将文件添加到字符串中。它确保您正在构建的路径是有效的。 文件:这是对目录或文件的引用。用于修改文件、打开文件等。如果将它们合并到一个类中会更容易 - 它们真的很混乱:D
希望对你有帮助:)
(我只是看了一下文档 - 看看 docs.oracle.com)
【讨论】:
【参考方案5】:文件是本地文件系统中实体的抽象表示。
路径通常是一个字符串,指示文件在文件系统中的位置。它通常不包括文件名。所以 c:\documents\mystuff\stuff.txt 将有一个值为“C:\documents\mystuff”的路径显然绝对文件名和路径的格式会因文件系统而异。
URL 是 URI 的子集,其中 URL 通常表示可通过 http 访问的资源。我不认为有任何关于什么时候必须是 URI 和 URL 的铁定规则。 URI 是“protocol://resource-identifier”形式的字符串,例如 bitcoin://params、http://something.com?param=value。 URL 之类的类通常包装字符串并提供 String 没有理由提供的实用方法。
没有资源之类的东西,至少在您所说的意义上不是。仅仅因为一个方法被命名为 getResource 并不意味着它返回一个 Resource 类型的对象。
最终确定类的方法做什么的最好方法是在代码中创建它的实例,调用方法,然后在调试模式下单步执行或将结果发送到 System.out。
【讨论】:
您对“路径”的定义与OP上下文中的“路径”概念不对应以上是关于Java中的资源、URI、URL、路径和文件有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
Thread.currentThread().getContextClassLoader().getResourceAsStream()读取配置文件
用Thread.currentThread().getContextClassLoader().getResourceAsStream读取配置文件