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

2022-08-31 10:11:18

我现在正在看一段Java代码,它将路径作为字符串,并使用获取其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)不够?(还有资源对象吗?

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


答案 1

我现在完全困惑 - 主要是因为术语,我猜。有人可以引导我了解差异,或者提供一些防假材料的链接吗?特别是URI到URL和资源到文件?对我来说,感觉它们应该分别是一回事......

这个术语令人困惑,有时令人困惑,并且主要是从Java作为API和平台随着时间的推移而演变而来的。要理解这些术语的含义,重要的是要认识到影响Java设计的两件事:

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

我将介绍这些概念以及它们是如何形成的。在那之后,我会回答你的其他具体问题,因为我可能不得不在第一部分中提到一些东西。

什么是“资源”?

可以定位和读取的抽象通用数据。粗略地说,Java用它来指代一个“文件”,它可能不是一个文件,但确实代表了一段命名的数据。它在Java中没有直接的类或接口表示,但由于其属性(可定位,可读),它通常由URL表示。

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

不幸的是,因为“resource”在这个解释之外也是一个有用的通用术语,它也被用来命名非常具体的东西(例如.class ResourceBundleUIResourceResource),从这个意义上说,这些东西不是资源。

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

文件 (java.io,1.0)

文件和目录路径名的抽象表示形式。

File 类表示可通过平台的本机文件系统访问的资源。它只包含文件的名称,因此它实际上更像是主机平台根据其自己的设置,规则和语法解释的路径(请参阅后面)。

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

网址(java.net,1.0)

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

与资源的概念一起,URL 表示该资源的方式与 File 类表示主机平台中的文件的方式相同:作为指向资源的结构化字符串。URL还包含一个方案,该方案提示如何访问资源(“file:”是“询问主机平台”),因此允许通过HTTP,FTP,JAR内部等指向资源。

不幸的是,URL有自己的语法和术语,包括使用“file”和“path”。如果 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)

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

新的文件 API(在 Path 接口中以图标形式显示)提供了比 File 类更大的灵活性。Path 接口是 File 类的抽象,是 New IO File API 的一部分。File必然指向主机平台所理解的“文件”,而Path则更通用:它表示任意文件系统中的文件(资源)。

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

主机平台通过“默认文件系统”表示;调用 时,您将在默认文件系统上获得一个 Path。File.toPath


现在,如果我有一个定位器引用了jar文件中的类或包,这两者(即路径和文件字符串)会有所不同吗?

不可能。如果 jar 文件位于本地文件系统上,则不应具有查询组件,因此应返回相同的结果。但是,请选择您需要的那个:文件URL通常可能没有查询组件,但我可以肯定添加一个。URL.getPathURL.getFile

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

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

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

(是否有 Resource 对象?

没有。有很多类似的东西,但它们不是意义上的资源。ClassLoader.getResource


答案 2

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


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

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

在Java中,它只是一个用于操作通用标识符本身的数据结构。URI

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

URL 可以指向文件系统资源,您可以使用协议为每个文件系统资源构造 URL(因此<->关系)。file://FileURL

另请注意,这与 无关。URL#getFilejava.io.File


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

这就够了。仅当要将资源传递给只能处理文件的某个组件时,才需要从中获取资源。但是,并非所有资源 URL 都可以转换为 s。FileFile

是否存在资源对象?

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