Qual è la differenza tra una risorsa, un URI, un URL, un percorso e un file in Java?


96

Sto guardando un pezzo di codice Java in questo momento, e prende un percorso come una stringa e ottiene il suo URL usando URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);, quindi chiama String path = resource.getPath()e infine viene eseguito new File(path);.

Oh, e ci sono anche chiamate a URL url = resource.toURI();e String file = resource.getFile().

In questo momento sono totalmente confuso, soprattutto a causa della terminologia, immagino. Qualcuno può guidarmi attraverso le differenze o fornire alcuni collegamenti a materiale a prova di manichino? Soprattutto URI all'URL e Risorsa al file ? Per me, sembra che dovrebbero essere la stessa cosa, rispettivamente ...

La differenza tra getFile()e getPath()è spiegata qui: Qual è la differenza tra url.getFile () e getpath ()? (È interessante notare che entrambi sembrano restituire Strings, il che probabilmente aggiunge molto al mio stato d'animo ...)

Ora, se ho un localizzatore che fa riferimento a una classe oa un pacchetto in un file jar, questi due (cioè il percorso di un file stringhe) differiranno?

resource.toString()ti darei jar:file:/C:/path/to/my.jar!/com/example/, dopotutto (nota il punto esclamativo).

La differenza tra URI e URL in Java è che il primo non codifica gli spazi? Cfr. File, URI e URL in conflitto in Java (questa risposta spiega abbastanza bene la differenza concettuale generale tra i due termini: gli URI identificano e gli URL individuano; )

Infine - e soprattutto - perché ho bisogno di Fileoggetto; perché una risorsa ( URL) non è sufficiente? (E c'è un oggetto Risorsa?)

Scusa se questa domanda è un po 'disorganizzata; riflette solo la confusione che ho ... :)


5
E non hai nemmeno iniziato a guardare Pathe FileSystem da NIO :)
eckes l'

2
@eckes Un mal di testa alla volta, per favore. ;)
Christian

1
Bene, nel contesto della tua domanda File / URL + URI non sono correlati. Uno è un mezzo per nominare e operare sui file, l'altro è un metodo per nominare e leggere dalle risorse (che possono essere file). I metodi getFile e getPath si occupano dei componenti di un URL che sono denominati (in modo confuso) come oggetti file. Le risorse del programma di caricamento classi non sono rappresentate come file poiché possono avere origini diverse (o essere nidificate in file JAR).
Eckes

1
Vorrei notare che è improbabile che questo codice funzioni come previsto. A URLè opaco , come si mostra jar:file:, cioè una risorsa in un .jararchivio. Colpendolo in a Fileè molto improbabile che risulti utile.
Boris the Spider

1
Il cuore del tuo problema è che le parole risorsa e percorso possono avere significati diversi, a seconda del contesto.
Raedwald

Risposte:


43

AGGIORNAMENTO 12-04-2017 Controlla la risposta di JvR in quanto contiene una spiegazione più esaustiva ed esatta!


Tieni presente che non mi considero competente al 100% per rispondere, tuttavia ecco alcuni commenti:

  • File rappresenta un file o una directory accessibile tramite file system
  • risorsa è un termine generico per un oggetto dati che può essere caricato dall'applicazione
    • di solito le risorse sono file distribuiti con l'applicazione / libreria e caricati tramite meccanismo di caricamento delle classi (quando risiedono nel percorso delle classi)
  • URL#getPathè getter sulla parte del percorso di URL ( protocol://host/path?query)
  • URL#getFile come da JavaDoc restituisce path+query

In Java, URIè solo una struttura dati per manipolare lo stesso identificatore generico.

URLd'altra parte è davvero un localizzatore di risorse e offre funzionalità per leggere effettivamente la risorsa tramite i messaggi registrati URLStreamHandler.

Gli URL possono portare a risorse del file system ed è possibile costruire URL per ogni risorsa del file system utilizzando il file://protocollo (da qui la relazione File<-> URL).

Inoltre, tieni presente che ciò URL#getFilenon è correlato a java.io.File.


Perché ho bisogno di un oggetto File; perché una risorsa (URL) non è sufficiente?

È abbastanza. Solo se vuoi passare la risorsa a qualche componente che può funzionare solo con i file, devi ottenerlo File. Tuttavia non tutti gli URL delle risorse possono essere convertiti in Files.

E c'è un oggetto Risorsa?

Dal punto di vista della JRE, è solo un termine. Alcuni framework forniscono questa classe (es. Spring's Resource ).


5
C'è anche java.nio.file.Path, che è fondamentalmente un sostituto (Java 7+) java.io.File, poiché quest'ultima API era apparentemente mal pensata nei primi giorni di Java.
ntoskrnl

1
In generale, dovresti ridurre al minimo l'utilizzo dell'URL a meno che non sia assolutamente necessario. Il motivo è che i metodi uguale e hashCode dell'URL sono implementati in modo sorprendente: bloccano le chiamate ai metodi.
kibibyte

3
@kibibyte: mi aspetto che la chiamata si blocchi, che abbia un'implementazione asincrona di hashcode ed è uguale ora che sarebbe molto inquietante. Penso che quello che volevi dire è che le chiamate proveranno a risolvere l'host per trovare se sono equivalenti e quindi potrebbero potenzialmente bloccare le chiamate di rete.
Newtopian

50

In questo momento sono totalmente confuso, soprattutto a causa della terminologia, immagino. Qualcuno può guidarmi attraverso le differenze o fornire alcuni collegamenti a materiale a prova di manichino? Soprattutto URI all'URL e Risorsa al file? Per me, sembra che dovrebbero essere la stessa cosa, rispettivamente ...

La terminologia è confusa e talvolta sconcertante, e per lo più nasce dall'evoluzione nel tempo sia di Java come API che come piattaforma. Per capire come questi termini abbiano significato quello che fanno, è importante riconoscere due cose che influenzano il design di Java:

  • Compatibilità con le versioni precedenti. Le vecchie applicazioni dovrebbero essere eseguite su installazioni più recenti, idealmente senza modifiche. Ciò significa che una vecchia API (con i suoi nomi e la terminologia) deve essere mantenuta attraverso tutte le versioni più recenti.
  • Cross-platform. L'API dovrebbe fornire un'astrazione utilizzabile della sua piattaforma sottostante, che si tratti di un sistema operativo o di un browser.

Descriverò i concetti e come sono nati. Risponderò alle tue altre domande specifiche dopo, perché potrei dover fare riferimento a qualcosa nella prima parte.

Cos'è una "risorsa"?

Un dato astratto e generico che può essere individuato e letto. Detto in modo approssimativo, Java lo usa per fare riferimento a un "file" che potrebbe non essere un file ma che rappresenta un dato dato. Non ha una rappresentazione di classe o interfaccia diretta in Java , ma a causa delle sue proprietà (individuabili, leggibili) è spesso rappresentato da un URL.

Poiché uno dei primi obiettivi di progettazione di Java era quello di essere eseguito all'interno di un browser, come applicazione sandbox (applet!) Con diritti / privilegi / autorizzazione di sicurezza molto limitati, Java fa una chiara differenza (teorica) tra un file (qualcosa sul locale file system) e una risorsa (qualcosa che deve leggere). Questo è il motivo per cui la lettura di qualcosa relativo all'applicazione (icone, file di classe e così via) viene eseguita tramite ClassLoader.getResourcee non tramite la classe File.

Sfortunatamente, poiché "risorsa" è anche un termine generico utile al di fuori di questa interpretazione, è anche usato per nominare cose molto specifiche (es. Classe ResourceBundle , UIResource , Resource ) che non sono, in questo senso, una risorsa.

Le classi principali che rappresentano (un percorso per) una risorsa sono java.nio.file.Path , java.io.File , java.net.URI e java.net.URL .

File (java.io, 1.0)

Una rappresentazione astratta di nomi di percorso di file e directory.

La classe File rappresenta una risorsa raggiungibile tramite il file system nativo della piattaforma . Contiene solo il nome del file, quindi è in realtà più un percorso (vedere più avanti) che la piattaforma host interpreta in base alle proprie impostazioni, regole e sintassi.

Nota che File non deve puntare a qualcosa di locale , ma solo a qualcosa che la piattaforma host comprende nel contesto dell'accesso ai file, ad esempio un percorso UNC in Windows. Se monti un file ZIP come file system nel tuo sistema operativo, File leggerà perfettamente le voci contenute.

URL (java.net, 1.0)

L'URL della classe rappresenta un Uniform Resource Locator, un puntatore a una "risorsa" sul World Wide Web. Una risorsa può essere qualcosa di semplice come un file o una directory, oppure può essere un riferimento a un oggetto più complicato, come una query a un database o a un motore di ricerca.

In tandem con il concetto di risorsa, l'URL rappresenta quella risorsa nello stesso modo in cui la classe File rappresenta un file nella piattaforma host: come una stringa strutturata che punta a una risorsa. L'URL contiene inoltre uno schema che suggerisce come raggiungere la risorsa (con "file:" che è "chiedi alla piattaforma host") e quindi consente di puntare alle risorse tramite HTTP, FTP, all'interno di un JAR e quant'altro.

Sfortunatamente, gli URL hanno una propria sintassi e terminologia, incluso l'uso di "file" e "percorso". Nel caso in cui l'URL sia un file-URL, URL.getFile restituirà una stringa identica alla stringa del percorso del file di riferimento.

Class.getResource restituisce un URL: è più flessibile del file restituito e ha soddisfatto le esigenze del sistema come immaginato all'inizio degli anni '90.

URI (java.net, 1.4)

Rappresenta un riferimento URI (Uniform Resource Identifier).

L'URI è una (leggera) astrazione sull'URL. La differenza tra URI e URL è concettuale e per lo più accademica, ma l'URI è meglio definito in senso formale e copre una gamma più ampia di casi d'uso. Poiché URL e URI sono / non erano la stessa cosa, è stata introdotta una nuova classe per rappresentarli, con i metodi URI.toURL e URL.toURI per spostarsi tra l'uno e l'altro.

In Java, la principale differenza tra URL e URI è che un URL ha l'aspettativa di essere risolvibile , qualcosa da cui l'applicazione potrebbe desiderare un InputStream; un URI è trattato più come una cosa astratta che potrebbe indicare qualcosa di risolvibile (e di solito lo fa), ma cosa significa e come raggiungerlo sono più aperti al contesto e all'interpretazione.

Percorso (java.nio.file, 1.7)

Un oggetto che può essere utilizzato per individuare un file in un file system. Tipicamente rappresenterà un percorso file dipendente dal sistema.

La nuova API di file, iconificata nell'interfaccia Path, consente una flessibilità molto maggiore di quella che la classe File potrebbe offrire. L'interfaccia Path è un'astrazione della classe File e fa parte della New IO File API . Dove File punta necessariamente a un "file" come inteso dalla piattaforma host, Path è più generico: rappresenta un file (risorsa) in un file system arbitrario .

Path elimina la dipendenza dal concetto di file della piattaforma host. Potrebbe essere una voce in un file ZIP, un file raggiungibile tramite FTP o SSH-FS, una rappresentazione multi-root del classpath dell'applicazione, o davvero qualsiasi cosa che possa essere rappresentata in modo significativo attraverso l'interfaccia FileSystem e il suo driver, FileSystemProvider. Porta la potenza del "montaggio" dei file system nel contesto di un'applicazione Java.

La piattaforma host è rappresentata attraverso il "file system predefinito"; quando chiami File.toPath, ottieni un percorso sul file system predefinito.


Ora, se ho un localizzatore che fa riferimento a una classe oa un pacchetto in un file jar, questi due (cioè il percorso di un file stringhe) differiranno?

Improbabile. Se il file jar si trova sul file system locale, non si dovrebbe avere un componente di query, quindi URL.getPathe URL.getFilenecessario restituire lo stesso risultato. Tuttavia, scegli quello che ti serve: gli URL dei file potrebbero non avere in genere componenti di query, ma potrei sicuramente aggiungerne uno comunque.

Infine, e soprattutto, perché ho bisogno di un oggetto File; perché una risorsa (URL) non è sufficiente?

L'URL potrebbe non essere sufficiente perché File ti dà accesso a dati di manutenzione come permessi (leggibili, scrivibili, eseguibili), tipo di file (sono una directory?) E la possibilità di cercare e manipolare il file system locale. Se queste sono le funzionalità di cui hai bisogno, allora File o Path le forniscono.

Non hai bisogno di File se hai accesso a Path. Alcune API meno recenti potrebbero richiedere File, tuttavia.

(E c'è un oggetto Risorsa?)

No, non c'è. Ci sono molte cose chiamate in questo modo, ma non sono una risorsa nel senso di ClassLoader.getResource.


Wow, molto accurato. Sto solo esaminandolo, ma ho già la prima domanda di follow-up: quando dici che un file "contiene solo il nome del file", non contraddire la tua affermazione iniziale che è "Una rappresentazione astratta di nomi di percorso di file e directory" - iemore?
Christian

1
@Christian volevo dire "solo il nome" come in: non modella in alcun modo il contenuto del file; è semplicemente un sottile involucro attorno a una stringa. La parte "rappresentazione astratta" è citata dalla documentazione dell'API. ;)
JvR

Questa risposta merita di avere molti più voti positivi ... aggiornerà la mia risposta accettata per indirizzare i lettori a questa.
Pavel Horal

12

La risposta di Pavel Horal è carina.

Come dice lui, la parola "file" ha significati totalmente diversi (praticamente non correlati) in URL#getFilevs java.io.File- potrebbe essere questo parte della confusione.

Solo per aggiungere:

  • Una risorsa in Java è un concetto astratto, una fonte di dati che possono essere letti. La posizione (o indirizzo) di una risorsa è rappresentata in Java da un URLoggetto.

  • Una risorsa può corrispondere a un file normale nel filesystem locale (in particolare, quando URLinizia con file://). Ma una risorsa è più generale (può essere anche qualche file contenuto in un jar, o qualche dato da leggere dalla rete, o dalla memoria, oppure ...). Ed è anche più limitato, perché un File(oltre ad essere altre cose rispetto a un normale file: una directory, un collegamento) può anche essere creato e scritto.

  • Ricorda che in Java un Fileoggetto non rappresenta realmente "un file" ma la posizione (il nome completo, con percorso) di un file. Quindi, un Fileoggetto ti consente di individuare (e aprire) un file, in quanto URLti consente di accedere (e aprire) una risorsa. (Non esiste una Resourceclasse in Java per rappresentare una risorsa, ma nemmeno una per rappresentare un file! Ancora una volta: Filenon è un file, è il percorso di un file).


3

A quanto ho capito, potresti classificarli come segue:

Basato sul Web: URI e URL.

  • URL: un URL è una posizione definita all'interno (solo un normale indirizzo web come - stackoverflow.com)
  • URI: Ever URL è un URI. Ma gli URI possono anche contenere cose come "mailto:", quindi sono anche, beh, qualcosa di "script" direi.

E locale: risorsa, percorso e file

  • Risorsa: le risorse sono file all'interno del tuo jar. Sono usati per caricare file da barattoli / contenitori.
  • Percorso: un percorso è fondamentalmente una stringa. Ma viene fornito con alcune utili funzioni per concatenare più stringhe o aggiungere file a una stringa. Si assicura che il percorso che stai costruendo sia valido.
  • File: questo è un riferimento a una directory o un file. Viene utilizzato per modificare file, aprirli ecc.

Sarebbe più facile se venissero fusi in un'unica classe: creano davvero confusione: D

Spero che questo ti aiuta :)

(Ho appena dato un'occhiata alla documentazione - guarda docs.oracle.com)


0

Un file è una rappresentazione astratta di un'entità nel filesystem locale.

Un percorso è generalmente una stringa che indica la posizione di un file all'interno di un file system. Di solito non include il nome del file. Quindi c: \ documents \ mystuff \ stuff.txt avrebbe un percorso con il valore di "C: \ documents \ mystuff" Ovviamente il formato dei nomi di file e dei percorsi assoluti varierebbe enormemente da filesystem a filesystem.

L'URL è un sottoinsieme di URI con URL che di solito rappresenta le risorse accessibili tramite http. Non penso che ci sia alcun tipo di regola ferrea su quando qualcosa deve essere un URI rispetto a un URL. Gli URI sono stringhe sotto forma di "protocol: // resource-identifier" come bitcoin: // params, http://something.com?param=value . Classi come URL generalmente racchiudono la stringa e forniscono metodi di utilità che String non avrebbe motivo di fornire.

Nessuna cosa come Risorsa, almeno non nel senso di cui parli. Solo perché un metodo è denominato getResource non significa che restituisca un oggetto di tipo Resource.

In definitiva, il modo migliore per capire cosa fanno i metodi di una classe è crearne un'istanza nel codice, chiamare i metodi e quindi passare in modalità di debug o inviare i risultati a System.out.


La tua definizione di "percorso" NON corrisponde al concetto di "percorso" nel contesto OP
Leonbloy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.