¿Cuál es la diferencia entre un recurso, URI, URL, ruta y archivo en Java?

95

Estoy viendo un fragmento de código Java en este momento, y toma una ruta como una Cadena y obtiene su URL usando URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);, luego llama String path = resource.getPath()y finalmente se ejecuta new File(path);.

Ah, y también hay llamadas a URL url = resource.toURI();y String file = resource.getFile().

Estoy totalmente confundido en este momento, sobre todo por la terminología, supongo. ¿Alguien puede explicarme las diferencias o proporcionar algunos enlaces a material a prueba de falsificaciones? ¿Especialmente URI a URL y recurso a archivo ? Para mí, parece que deberían ser lo mismo, respectivamente ...

La diferencia entre getFile()y getPath()se explica aquí: ¿Cuál es la diferencia entre url.getFile () y getpath ()? (Curiosamente, ambos parecen devolver Strings, lo que probablemente agrega mucho a mi estado de ánimo ...)

Ahora, si tengo un localizador que hace referencia a una clase o paquete en un archivo jar, ¿diferirán esos dos (es decir, la ruta y las cadenas de archivo)?

resource.toString()te daría jar:file:/C:/path/to/my.jar!/com/example/, después de todo (nota el signo de exclamación).

¿Es la diferencia entre URI y URL en Java que el primero no codifica espacios? Cf. Archivos, URI y URL que entran en conflicto en Java (esta respuesta explica bastante bien la diferencia conceptual general entre los dos términos: los URI identifican y las URL localizan; )

Por último, y lo más importante, ¿por qué necesito un Fileobjeto? ¿Por qué un Resource ( URL) no es suficiente? (¿Y hay un objeto de recurso?)

Lo siento si esta pregunta está un poco desorganizada; solo refleja la confusión que tengo ... :)

cristiano
fuente
5
Y ni siquiera comenzó a mirar Pathy FileSystem de NIO :)
eckes
2
@eckes Un dolor de cabeza a la vez, por favor. ;)
Christian
1
Bueno, en el contexto de su pregunta, el archivo / URL + URI no están relacionados. Uno es un medio para nombrar y operar en archivos, el otro es un método para nombrar y leer recursos (que pueden ser archivos). Los métodos getFile y getPath tratan con los componentes de una URL que se denominan (confusamente) como objetos de archivo. Los recursos del cargador de clases no se representan como archivos, ya que pueden tener diferentes orígenes (o estar anidados en archivos JAR).
eckes
1
Me gustaría señalar que es poco probable que este código funcione según lo previsto. A URLes opaco , como lo muestra jar:file:, es decir, un recurso en un .jararchivo. FileEs muy poco probable que meter eso en un resultado en algo útil.
Boris the Spider
1
El meollo de su problema es que las palabras recurso y ruta pueden tener diferentes significados, según el contexto.
Raedwald

Respuestas:

43

ACTUALIZACIÓN 2017-04-12 ¡ Compruebe la respuesta de JvR ya que contiene una explicación más exhaustiva y exacta!


Tenga en cuenta que no me considero 100% competente para responder, pero sin embargo, aquí hay algunos comentarios:

  • File representa un archivo o directorio accesible a través del sistema de archivos
  • recurso es un término genérico para un objeto de datos que puede ser cargado por la aplicación
    • Por lo general, los recursos son archivos distribuidos con la aplicación / biblioteca y cargados a través del mecanismo de carga de clases (cuando residen en class-path)
  • URL#getPathes getter en la parte de la ruta de URL ( protocol://host/path?query)
  • URL#getFile según devoluciones de JavaDoc path+query

En Java, URIes solo una estructura de datos para manipular el identificador genérico en sí.

URLpor otro lado, es realmente un localizador de recursos y le ofrece funciones para leer el recurso a través de correos electrónicos registrados URLStreamHandler.

Las URL pueden conducir a recursos del sistema de archivos y puede construir una URL para cada recurso del sistema de archivos utilizando el file://protocolo (de ahí la relación File<-> URL).

También tenga en cuenta que eso URL#getFileno está relacionado con java.io.File.


¿Por qué necesito el objeto File; ¿Por qué no es suficiente un recurso (URL)?

Es suficiente. Solo si desea pasar el recurso a algún componente que solo puede funcionar con archivos, debe obtenerlo File. Sin embargo, no todas las URL de recursos se pueden convertir a Files.

¿Y hay un objeto de recurso?

Desde el punto de vista de JRE, es solo un término. Algunos marcos le proporcionan dicha clase (por ejemplo, Spring's Resource ).

Pavel Horal
fuente
5
También está java.nio.file.Path, que es básicamente un reemplazo de (Java 7+) java.io.File, ya que la última API aparentemente fue mal pensada en los primeros días de Java.
ntoskrnl
1
Generalmente, debe minimizar el uso de URL a menos que sea absolutamente necesario. La razón es que los métodos equals y hashCode de la URL se implementan de una manera sorprendente: están bloqueando llamadas a métodos.
kibibyte
3
@kibibyte: Esperaría que la llamada se bloqueara, que tuviera una implementación asincrónica de hashcode e igual ahora, eso sería muy inquietante. Creo que lo que quiso decir es que las llamadas intentarán resolver el host para encontrar si son equivalentes y, por lo tanto, podrían bloquear llamadas de red.
Newtopian
50

Estoy totalmente confundido en este momento, sobre todo por la terminología, supongo. ¿Alguien puede explicarme las diferencias o proporcionar algunos enlaces a material a prueba de falsificaciones? ¿Especialmente URI a URL y recurso a archivo? Para mí, parece que deberían ser lo mismo, respectivamente ...

La terminología es confusa y a veces confusa, y en su mayoría nace de la evolución de Java como API y como plataforma a lo largo del tiempo. Para comprender cómo estos términos llegaron a significar lo que hacen, es importante reconocer dos cosas que influyen en el diseño de Java:

  • Compatibilidad al revés. Las aplicaciones antiguas deberían ejecutarse en instalaciones más nuevas, idealmente sin modificaciones. Esto significa que una API antigua (con sus nombres y terminología) debe mantenerse en todas las versiones más nuevas.
  • Multiplataforma. La API debe proporcionar una abstracción utilizable de su plataforma subyacente, ya sea un sistema operativo o un navegador.

Analizaré los conceptos y cómo surgieron. Responderé a sus otras preguntas específicas después de eso, porque es posible que tenga que referirme a algo en la primera parte.

¿Qué es un "recurso"?

Un dato abstracto y genérico que se puede localizar y leer. En términos generales, Java usa esto para referirse a un "archivo" que puede no ser un archivo pero que representa un dato con nombre. No tiene una clase directa o una representación de interfaz en Java , pero debido a sus propiedades (localizable, legible) a menudo se representa mediante una URL.

Debido a que uno de los primeros objetivos de diseño de Java era ejecutarse dentro de un navegador, como una aplicación de espacio aislado (¡applets!) Con derechos / privilegios / autorización de seguridad muy limitados, Java marca una diferencia clara (teórica) entre un archivo (algo en el local sistema de archivos) y un recurso (algo que necesita leer). Esta es la razón por la que leer algo relativo a la aplicación (iconos, archivos de clase, etc.) se realiza a ClassLoader.getResourcetravés de la clase File y no a través de ella.

Desafortunadamente, debido a que "recurso" también es un término genérico útil fuera de esta interpretación, también se usa para nombrar cosas muy específicas (por ejemplo, clase ResourceBundle , UIResource , Resource ) que no son, en este sentido, un recurso.

Las clases principales que representan (una ruta a) un recurso son java.nio.file.Path , java.io.File , java.net.URI y java.net.URL .

Archivo (java.io, 1.0)

Una representación abstracta de nombres de rutas de archivos y directorios.

La clase File representa un recurso al que se puede acceder a través del sistema de archivos nativo de la plataforma . Contiene solo el nombre del archivo, por lo que en realidad es más una ruta (ver más adelante) que la plataforma host interpreta de acuerdo con su propia configuración, reglas y sintaxis.

Tenga en cuenta que el archivo no necesita apuntar a algo local , solo algo que la plataforma de host entiende en el contexto del acceso al archivo, por ejemplo, una ruta UNC en Windows. Si monta un archivo ZIP como un sistema de archivos en su sistema operativo, File leerá sus entradas contenidas sin problemas.

URL (java.net, 1.0)

La URL de la clase representa un localizador uniforme de recursos, un puntero a un "recurso" en la World Wide Web. Un recurso puede ser algo tan simple como un archivo o un directorio, o puede ser una referencia a un objeto más complicado, como una consulta a una base de datos o un motor de búsqueda.

Junto con el concepto de recurso, la URL representa ese recurso de la misma manera que la clase File representa un archivo en la plataforma de host: como una cadena estructurada que apunta a un recurso. La URL además contiene un esquema que sugiere cómo llegar al recurso (con "archivo:" siendo "preguntar a la plataforma de host"), y así permite apuntar a recursos a través de HTTP, FTP, dentro de un JAR y otras cosas.

Desafortunadamente, las URL vienen con su propia sintaxis y terminología, incluido el uso de "archivo" y "ruta". En caso de que la URL sea una URL de archivo, URL.getFile devolverá una cadena idéntica a la cadena de ruta del archivo referenciado.

Class.getResource devuelve una URL: es más flexible que devolver un archivo, y ha respondido a las necesidades del sistema como se imaginaba a principios de la década de 1990.

URI (java.net, 1.4)

Representa una referencia de identificador uniforme de recursos (URI).

URI es una abstracción (leve) sobre URL. La diferencia entre URI y URL es conceptual y principalmente académica, pero URI se define mejor en un sentido formal y cubre una gama más amplia de casos de uso. Debido a que URL y URI son / no eran lo mismo, se introdujo una nueva clase para representarlos, con los métodos URI.toURL y URL.toURI para moverse entre uno y otro.

En Java, la principal diferencia entre URL y URI es que una URL conlleva la expectativa de poder resolverse , algo de lo que la aplicación podría querer un InputStream; un URI se trata más como una cosa abstracta que puede apuntar a algo que se puede resolver (y generalmente lo hace), pero lo que significa y cómo llegar a él está más abierto al contexto y la interpretación.

Ruta (java.nio.file, 1.7)

Objeto que puede usarse para ubicar un archivo en un sistema de archivos. Por lo general, representará una ruta de archivo dependiente del sistema.

La nueva API de archivo, iconificada en la interfaz Path, permite una flexibilidad mucho mayor que la que podría ofrecer la clase File. La interfaz Path es una abstracción de la clase File y es parte de la API New IO File . Donde Archivo necesariamente apunta a un "archivo" como lo entiende la plataforma de host, Path es más genérico: representa un archivo (recurso) en un sistema de archivos arbitrario .

Path elimina la dependencia del concepto de archivo de la plataforma de host. Podría ser una entrada en un archivo ZIP, un archivo accesible a través de FTP o SSH-FS, una representación de múltiples raíces de la ruta de clases de la aplicación, o realmente cualquier cosa que se pueda representar de manera significativa a través de la interfaz FileSystem y su controlador, FileSystemProvider. Aporta el poder de "montar" sistemas de archivos en el contexto de una aplicación Java.

La plataforma de host se representa a través del "sistema de archivos predeterminado"; cuando llama File.toPath, obtiene una ruta en el sistema de archivos predeterminado.


Ahora, si tengo un localizador que hace referencia a una clase o paquete en un archivo jar, ¿diferirán esos dos (es decir, la ruta y las cadenas de archivo)?

Improbable. Si el archivo JAR está en el sistema de archivos local, no debe tener un componente de consulta, por lo que URL.getPathy URL.getFiledebe devolver el mismo resultado. Sin embargo, elija el que necesita: las URL de archivo pueden no tener normalmente componentes de consulta, pero seguro que podría agregar uno de todos modos.

Por último, y lo más importante, ¿por qué necesito el objeto File; ¿Por qué no es suficiente un recurso (URL)?

Es posible que la URL no sea suficiente porque Archivo le brinda acceso a datos de mantenimiento como permisos (legibles, de escritura, ejecutables), tipo de archivo (¿soy un directorio?) Y la capacidad de buscar y manipular el sistema de archivos local. Si estas son características que necesita, File o Path se las proporcionan.

No necesita Archivo si tiene acceso a Ruta. Sin embargo, algunas API más antiguas pueden requerir Archivo.

(¿Y hay un objeto de recurso?)

No, no lo hay. Hay muchas cosas nombradas así, pero no son un recurso en el sentido de ClassLoader.getResource.

JvR
fuente
Vaya, muy completo. Solo lo reviso, pero ya tengo la primera pregunta de seguimiento: cuando dice que un archivo "contiene solo el nombre del archivo", no contradiga su declaración inicial de que es "una representación abstracta de los nombres de ruta de archivos y directorios". - ¿más?
Christian
1
@Christian Quise decir "solo el nombre" como en: no modela de ninguna manera el contenido del archivo; es simplemente una fina envoltura alrededor de una cuerda. La parte de "representación abstracta" se cita en los documentos de la API. ;)
JvR
Esta respuesta merece tener muchos más votos positivos ... actualizaré mi respuesta aceptada para señalar a los lectores esta.
Pavel Horal
12

La respuesta de Pavel Horal es agradable.

Como él dice, la palabra "archivo" tiene significados totalmente diferentes (prácticamente sin relación) en URL#getFilevs. java.io.FilePuede que eso sea parte de la confusión.

Solo para agregar:

  • Un recurso en Java es un concepto abstracto, una fuente de datos que se puede leer. La ubicación (o dirección) de un recurso está representada en Java por un URLobjeto.

  • Un recurso puede corresponder a un archivo normal en el sistema de archivos local (específicamente, cuando URLcomienza con file://). Pero un recurso es más general (también puede ser algún archivo almacenado en un jar, o algunos datos para leer de la red, o de la memoria, o ...). Y también es más limitado, porque File(además de ser algo más que un archivo normal: un directorio, un enlace) también se puede crear y escribir.

  • Recuerde que en Java un Fileobjeto no representa realmente "un archivo" sino la ubicación (el nombre completo, con la ruta) de un archivo. Por lo tanto, un Fileobjeto le permite ubicar (y abrir) un archivo, ya URLque le permite acceder (y abrir) un recurso. (¡No hay una Resourceclase en Java para representar un recurso, pero tampoco hay una para representar un archivo! Una vez más: Fileno es un archivo, es la ruta de un archivo).

Leonbloy
fuente
3

Según tengo entendido, podría categorizarlos de la siguiente manera:

Basado en web: URI y URL.

  • URL: una URL es una ubicación definida en el interno (solo una dirección web normal como - stackoverflow.com)
  • URI: cada URL es un URI. Pero los URI también pueden contener cosas como "mailto:", por lo que también son, bueno, algo así como un "script", diría yo.

Y local: recurso, ruta y archivos

  • Recurso: los recursos son archivos dentro de su jar. Se utilizan para cargar archivos de frascos / contenedores.
  • Ruta: una ruta es básicamente una cadena. Pero viene con algunas funciones útiles para concatenar múltiples cadenas o agregar archivos a una cadena. Se asegura de que el camino que está construyendo sea válido.
  • Archivo: es una referencia a un directorio o archivo. Se utiliza para modificar archivos, abrirlos, etc.

Sería más fácil si se fusionaran en una sola clase; son realmente confusos: D

Espero que esto te ayude :)

(Acabo de echar un vistazo a la documentación, mire docs.oracle.com)

Cyphrags
fuente
0

Un archivo es una representación abstracta de una entidad en el sistema de archivos local.

Una ruta es generalmente una cadena que indica la ubicación de un archivo dentro de un sistema de archivos. Por lo general, no incluye el nombre del archivo. Entonces c: \ documentos \ mystuff \ stuff.txt tendría una ruta con el valor de "C: \ documentos \ mystuff" Obviamente, el formato de los nombres de archivo absolutos y las rutas variaría enormemente de un sistema de archivos a otro.

URL es un conjunto de URI con URL que generalmente representa recursos accesibles a través de http. No creo que haya ningún tipo de regla rígida sobre cuándo algo tiene que ser un URI frente a una URL. Los URI son cadenas en forma de "protocolo: // identificador de recursos", como bitcoin: // params, http://something.com?param=value . Las clases como URL generalmente envuelven la cadena y proporcionan métodos de utilidad que String no tendría ninguna razón para proporcionar.

No existe el recurso, al menos no en el sentido del que estás hablando. El hecho de que un método se llame getResource no significa que devuelva un objeto de tipo Resource.

En última instancia, la mejor manera de averiguar qué hacen los métodos de una clase es crear una instancia de ella en su código, llamar a los métodos y luego pasar por el modo de depuración o enviar los resultados a System.out.

Jim W
fuente
Su definición de "ruta" NO corresponde al concepto de "ruta" en el contexto OP
leonbloy