Was ist der Unterschied zwischen einer Ressource, einem URI, einer URL, einem Pfad und einer Datei in Java?

95

Ich schaue mir gerade einen Teil des Java-Codes an, der einen Pfad als Zeichenfolge verwendet und dessen URL verwendet URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);, dann aufruft String path = resource.getPath()und schließlich ausführt new File(path);.

Oh, und es gibt auch Anrufe nach URL url = resource.toURI();und String file = resource.getFile().

Ich bin momentan total verwirrt - hauptsächlich wegen der Terminologie, denke ich. Kann mich bitte jemand durch die Unterschiede führen oder ein paar Links zu Dummy-Proof-Material bereitstellen? Besonders URI zu URL und Ressource zu Datei ? Für mich fühlt es sich so an, als ob sie dasselbe sein sollten ...

Der Unterschied zwischen getFile()und getPath()wird hier erklärt: Was ist der Unterschied zwischen url.getFile () und getpath ()? (Interessanterweise scheinen beide Strings zurückzugeben, was wahrscheinlich meinen Geisteszustand erheblich erweitert ...)

Wenn ich nun einen Locator habe, der auf eine Klasse oder ein Paket in einer JAR-Datei verweist, unterscheiden sich diese beiden (dh Pfad und Datei-Zeichenfolgen)?

resource.toString()würde Ihnen schließlich geben jar:file:/C:/path/to/my.jar!/com/example/(beachten Sie das Ausrufezeichen).

Ist der Unterschied zwischen URI und URL in Java, dass erstere keine Leerzeichen codieren? Vgl. Dateien, URIs und URLs, die in Java in Konflikt stehen (Diese Antwort erklärt den allgemeinen konzeptionellen Unterschied zwischen den beiden Begriffen ziemlich gut: URIs identifizieren und URLs lokalisieren; )

Schließlich - und vor allem - warum brauche ich ein FileObjekt? Warum reicht eine Ressource ( URL) nicht aus? (Und gibt es ein Ressourcenobjekt?)

Entschuldigung, wenn diese Frage etwas unorganisiert ist. es spiegelt nur die Verwirrung wider, die ich habe ... :)

Christian
quelle
5
Und Sie haben noch nicht einmal angefangen, sich PathFileSystem von NIO
anzuschauen
2
@ckes Bitte Kopfschmerzen nacheinander. ;)
Christian
1
Nun, im Kontext Ihrer Frage sind Datei / URL + URI nicht miteinander verbunden. Das eine ist ein Mittel zum Benennen und Bearbeiten von Dateien, das andere ist eine Methode zum Benennen und Lesen von Ressourcen (die Dateien sein können). Die Methoden getFile und getPath behandeln die Komponenten einer URL, die (verwirrenderweise) wie Dateiobjekte benannt sind. Classloader-Ressourcen werden nicht als Dateien dargestellt, da sie unterschiedliche Ursprünge haben können (oder in JAR-Dateien verschachtelt sein können).
eckes
1
Ich würde beachten, dass dieser Code wahrscheinlich nicht wie beabsichtigt funktioniert. A URList undurchsichtig - wie Sie zeigen jar:file:, dh eine Ressource in einem .jarArchiv. Es Fileist sehr unwahrscheinlich, dass etwas Nützliches daraus wird.
Boris die Spinne
1
Das Herzstück Ihres Problems ist, dass die Wörter Ressource und Pfad je nach Kontext unterschiedliche Bedeutungen haben können.
Raedwald

Antworten:

43

UPDATE 2017-04-12 Überprüfen Sie die Antwort von JvR, da sie ausführlichere und genauere Erklärungen enthält!


Bitte beachten Sie, dass ich mich nicht als 100% kompetent zur Beantwortung betrachte, aber dennoch hier einige Kommentare:

  • File stellt eine Datei oder ein Verzeichnis dar, auf die bzw. das über das Dateisystem zugegriffen werden kann
  • Ressource ist ein Oberbegriff für ein Datenobjekt, das von der Anwendung geladen werden kann
    • Normalerweise sind Ressourcen Dateien, die mit der Anwendung / Bibliothek verteilt und über den Klassenlademechanismus geladen werden (wenn sie sich im Klassenpfad befinden).
  • URL#getPathist Getter auf dem Pfad Teil von URL ( protocol://host/path?query)
  • URL#getFile gemäß JavaDoc zurück path+query

In Java URIist dies nur eine Datenstruktur zum Bearbeiten des generischen Bezeichners selbst.

URLAuf der anderen Seite ist es wirklich ein Ressourcen-Locator und bietet Ihnen Funktionen, um die Ressource tatsächlich über registrierte URLStreamHandlers zu lesen .

URLs können zu Dateisystemressourcen führen, und Sie können mithilfe eines file://Protokolls (daher File<-> URLBeziehung) eine URL für jede Dateisystemressource erstellen .

Beachten Sie auch, dass dies URL#getFilenichts damit zu tun hat java.io.File.


Warum brauche ich ein Dateiobjekt? Warum reicht eine Ressource (URL) nicht aus?

Es reicht. Nur wenn Sie die Ressource an eine Komponente übergeben möchten, die nur mit Dateien arbeiten kann, müssen Sie sie abrufen File. Es können jedoch nicht alle Ressourcen-URLs in Files konvertiert werden .

Und gibt es ein Ressourcenobjekt?

Aus Sicht der JRE ist es nur ein Begriff. Einige Frameworks bieten Ihnen eine solche Klasse (z. B. Spring's Resource ).

Pavel Horal
quelle
5
Es gibt auch java.nio.file.Path, was im Grunde ein (Java 7+) Ersatz für ist java.io.File, da die letztere API in den frühen Tagen von Java anscheinend schlecht durchdacht war.
Ntoskrnl
1
Im Allgemeinen sollten Sie die Verwendung von URLs minimieren, sofern dies nicht unbedingt erforderlich ist. Der Grund dafür ist, dass die Methoden equals und hashCode der URL auf überraschende Weise implementiert werden: Sie blockieren Methodenaufrufe.
Kibibyte
3
@kibibyte: Ich würde erwarten, dass der Aufruf blockiert, eine asynchrone Implementierung von Hashcode hat und jetzt gleich ist, was sehr beunruhigend wäre. Ich denke, Sie haben damit gemeint, dass die Anrufe versuchen, den Host aufzulösen, um festzustellen, ob sie gleichwertig sind, und daher möglicherweise blockierende Netzwerkanrufe tätigen könnten.
Newtopian
50

Ich bin momentan total verwirrt - hauptsächlich wegen der Terminologie, denke ich. Kann mich bitte jemand durch die Unterschiede führen oder ein paar Links zu Dummy-Proof-Material bereitstellen? Besonders URI zu URL und Ressource zu Datei? Für mich fühlt es sich so an, als ob sie dasselbe sein sollten ...

Die Terminologie ist verwirrend und manchmal verwirrend und basiert hauptsächlich auf der Entwicklung von Java als API und als Plattform im Laufe der Zeit. Um zu verstehen, wie diese Begriffe zu ihrer Bedeutung führten, ist es wichtig, zwei Dinge zu erkennen, die das Design von Java beeinflussen:

  • Abwärtskompatibilität. Alte Anwendungen sollten auf neueren Installationen ausgeführt werden, idealerweise ohne Änderungen. Dies bedeutet, dass eine alte API (mit ihren Namen und ihrer Terminologie) in allen neueren Versionen beibehalten werden muss.
  • Plattformübergreifend. Die API sollte eine verwendbare Abstraktion der zugrunde liegenden Plattform bereitstellen, unabhängig davon, ob es sich um ein Betriebssystem oder einen Browser handelt.

Ich werde durch die Konzepte gehen und wie sie entstanden sind. Ich werde Ihre anderen, spezifischen Fragen danach beantworten, da ich mich möglicherweise im ersten Teil auf etwas beziehen muss.

Was ist eine "Ressource"?

Ein abstraktes, allgemeines Datenelement, das gefunden und gelesen werden kann. Java verwendet dies, um auf eine "Datei" zu verweisen, die möglicherweise keine Datei ist, aber ein benanntes Datenelement darstellt. Es hat keine direkte Klassen- oder Schnittstellendarstellung in Java , aber aufgrund seiner Eigenschaften (lokalisierbar, lesbar) wird es häufig durch eine URL dargestellt.

Da eines der frühen Entwurfsziele von Java darin bestand, innerhalb eines Browsers als Sandbox-Anwendung (Applets!) Mit sehr eingeschränkten Rechten / Privilegien / Sicherheitsfreigaben ausgeführt zu werden, macht Java einen klaren (theoretischen) Unterschied zwischen einer Datei (etwas auf lokaler Ebene) Dateisystem) und eine Ressource (etwas, das es lesen muss). Aus diesem Grund erfolgt das Lesen von Informationen zur Anwendung (Symbole, Klassendateien usw.) über ClassLoader.getResourceund nicht über die File-Klasse.

Da "Ressource" auch außerhalb dieser Interpretation ein nützlicher Oberbegriff ist , wird es leider auch verwendet, um sehr spezifische Dinge (z. B. Klasse ResourceBundle , UIResource , Resource ) zu benennen , die in diesem Sinne keine Ressource sind.

Die Hauptklassen (ein Pfad zu) einer Ressource sind java.nio.file.Path , java.io.File , java.net.URI und java.net.URL .

Datei (java.io, 1.0)

Eine abstrakte Darstellung von Datei- und Verzeichnispfadnamen.

Die File-Klasse stellt eine Ressource dar, die über das native Dateisystem der Plattform erreichbar ist . Es enthält nur den Namen der Datei, es ist also eher ein Pfad (siehe später), den die Host-Plattform gemäß ihren eigenen Einstellungen, Regeln und Syntax interpretiert.

Beachten Sie, dass File nicht auf etwas Lokales verweisen muss, sondern nur auf etwas, das die Hostplattform im Kontext des Dateizugriffs versteht, z. B. einen UNC-Pfad in Windows. Wenn Sie eine ZIP-Datei als Dateisystem in Ihr Betriebssystem einbinden, liest File die darin enthaltenen Einträge einwandfrei.

URL (java.net, 1.0)

Die Klassen-URL stellt einen Uniform Resource Locator dar, einen Zeiger auf eine "Ressource" im World Wide Web. Eine Ressource kann so einfach wie eine Datei oder ein Verzeichnis sein oder ein Verweis auf ein komplizierteres Objekt, z. B. eine Abfrage an eine Datenbank oder eine Suchmaschine.

In Verbindung mit dem Konzept einer Ressource stellt die URL diese Ressource genauso dar wie die File-Klasse eine Datei auf der Host-Plattform: als strukturierte Zeichenfolge, die auf eine Ressource verweist. Die URL enthält außerdem ein Schema, das angibt, wie die Ressource erreicht werden kann (wobei "file:" "die Host-Plattform fragen" ist), und ermöglicht so das Zeigen auf Ressourcen über HTTP, FTP, innerhalb einer JAR und so weiter.

Leider haben URLs ihre eigene Syntax und Terminologie, einschließlich der Verwendung von "Datei" und "Pfad". Wenn die URL eine Datei-URL ist, gibt URL.getFile eine Zeichenfolge zurück, die mit der Pfadzeichenfolge der referenzierten Datei identisch ist.

Class.getResource Gibt eine URL zurück: Sie ist flexibler als die Rückgabe von Dateien und hat die Anforderungen des Systems erfüllt, wie sie in den frühen neunziger Jahren vorgestellt wurden.

URI (java.net, 1.4)

Stellt eine URI-Referenz (Uniform Resource Identifier) ​​dar.

URI ist eine (leichte) Abstraktion über URL. Der Unterschied zwischen URI und URL ist konzeptionell und meist akademisch, aber URI ist formal besser definiert und deckt ein breiteres Spektrum von Anwendungsfällen ab. Da URL und URI nicht dasselbe sind / waren, wurde eine neue Klasse eingeführt, um sie darzustellen, mit den Methoden URI.toURL und URL.toURI, um zwischen den beiden zu wechseln.

In Java besteht der Hauptunterschied zwischen URL und URI darin, dass eine URL die Erwartung hat, auflösbar zu sein , von der die Anwendung möglicherweise einen InputStream möchte. Ein URI wird eher wie ein abstraktes Ding behandelt, das auf etwas Auflösbares verweist (und dies normalerweise tut), aber was es bedeutet und wie man es erreicht, ist offener für Kontext und Interpretation.

Pfad (java.nio.file, 1.7)

Ein Objekt, mit dem eine Datei in einem Dateisystem gefunden werden kann. Es wird normalerweise einen systemabhängigen Dateipfad darstellen.

Die neue Datei-API, die in der Pfadoberfläche dargestellt ist, bietet eine viel größere Flexibilität, als die Dateiklasse bieten könnte. Die Pfadschnittstelle ist eine Abstraktion der File-Klasse und Teil der New IO File API . Wenn File notwendigerweise auf eine "Datei" verweist, wie sie von der Host-Plattform verstanden wird, ist Path allgemeiner: Es repräsentiert eine Datei (Ressource) in einem beliebigen Dateisystem.

Path nimmt die Abhängigkeit vom Konzept einer Datei auf der Host-Plattform. Dies kann ein Eintrag in einer ZIP-Datei sein, eine Datei, die über FTP oder SSH-FS erreichbar ist, eine mehrwurzelige Darstellung des Anwendungsklassenpfads oder wirklich alles, was über die FileSystem-Schnittstelle und ihren Treiber FileSystemProvider sinnvoll dargestellt werden kann. Es bringt die Fähigkeit, Dateisysteme in den Kontext einer Java-Anwendung zu "mounten".

Die Host-Plattform wird durch das "Standard-Dateisystem" dargestellt. Wenn Sie aufrufen File.toPath, erhalten Sie einen Pfad im Standarddateisystem.


Wenn ich nun einen Locator habe, der auf eine Klasse oder ein Paket in einer JAR-Datei verweist, unterscheiden sich diese beiden (dh Pfad und Datei-Zeichenfolgen)?

Unwahrscheinlich. Wenn die JAR - Datei auf dem lokalen Dateisystem ist, sollten Sie keine Abfragekomponente haben, so URL.getPathund URL.getFilesollte das gleiche Ergebnis zurück. Wählen Sie jedoch die gewünschte aus: Datei-URLs enthalten normalerweise keine Abfragekomponenten, aber ich könnte trotzdem eine hinzufügen.

Zuletzt - und vor allem - warum brauche ich ein Dateiobjekt? Warum reicht eine Ressource (URL) nicht aus?

Die URL reicht möglicherweise nicht aus, da Sie mit File Zugriff auf Verwaltungsdaten wie Berechtigungen (lesbar, beschreibbar, ausführbar), Dateityp (bin ich ein Verzeichnis?) Und die Möglichkeit haben, das lokale Dateisystem zu durchsuchen und zu bearbeiten. Wenn Sie diese Funktionen benötigen, stellen Sie sie mit Datei oder Pfad bereit.

Sie benötigen keine Datei, wenn Sie Zugriff auf Path haben. Für einige ältere APIs ist möglicherweise eine Datei erforderlich.

(Und gibt es ein Ressourcenobjekt?)

Nein, gibt es nicht. Es gibt viele ähnliche Dinge, aber sie sind keine Ressource im Sinne von ClassLoader.getResource.

JvR
quelle
Wow, sehr gründlich. Gehen Sie es einfach durch, haben Sie aber bereits die erste Folgefrage: Wenn Sie sagen, dass eine Datei "nur den Namen der Datei enthält", widersprechen Sie nicht Ihrer ursprünglichen Aussage, dass es sich um "eine abstrakte Darstellung von Datei- und Verzeichnispfadnamen" handelt. - mehr?
Christian
1
@Christian Ich meinte "nur den Namen" wie in: modelliert in keiner Weise den Inhalt der Datei; Es ist nur eine dünne Hülle um eine Schnur. Der Teil "Abstrakte Darstellung" wird aus den API-Dokumenten zitiert. ;)
JvR
Diese Antwort verdient viel mehr positive Stimmen ... wird meine akzeptierte Antwort aktualisieren, um die Leser auf diese zu verweisen.
Pavel Horal
12

Pavel Horals Antwort ist nett.

Wie er sagt, hat das Wort "Datei" in URL#getFilevs völlig unterschiedliche (praktisch nicht verwandte) Bedeutungen java.io.File- vielleicht ist das ein Teil der Verwirrung.

Nur um hinzuzufügen:

  • Eine Ressource in Java ist ein abstraktes Konzept, eine Datenquelle, die gelesen werden kann. Der Speicherort (oder die Adresse) einer Ressource wird in Java durch ein URLObjekt dargestellt.

  • Eine Ressource kann einer regulären Datei im lokalen Dateisystem entsprechen (insbesondere, wenn sie mit URLbeginnt file://). Eine Ressource ist jedoch allgemeiner (es kann sich auch um eine in einem JAR gespeicherte Datei oder um Daten handeln, die aus dem Netzwerk oder aus dem Speicher gelesen werden sollen, oder ...). Und es ist auch eingeschränkter, weil eine File(abgesehen davon, dass es sich nicht um eine normale Datei handelt: ein Verzeichnis, ein Link) auch erstellt und in diese geschrieben werden kann.

  • Denken Sie daran, dass in Java ein FileObjekt nicht wirklich "eine Datei" darstellt, sondern den Speicherort (den vollständigen Namen mit Pfad) einer Datei. Mit einem FileObjekt können Sie also eine Datei suchen (und öffnen), während URLSie auf eine Ressource zugreifen (und diese öffnen) können. ( ResourceIn Java gibt es keine Klasse, die eine Ressource darstellt, aber auch keine, die eine Datei darstellt! Noch einmal: Es Filehandelt sich nicht um eine Datei, sondern um den Pfad einer Datei.)

leonbloy
quelle
3

So wie ich sie verstehe, können Sie sie wie folgt kategorisieren:

Webbasiert: URIs und URLs.

  • URLs: Eine URL ist ein bestimmter Ort auf dem Internet (nur eine normale Webadresse wie - stackoverflow.com).
  • URIs: Jede URL ist eine URI. Aber URIs können auch Dinge wie "mailto:" enthalten, also sind sie auch so etwas wie ein "Skript", würde ich sagen.

Und lokal: Ressource, Pfad und Dateien

  • Ressource: Ressourcen sind Dateien in Ihrem Glas. Sie werden verwendet, um Dateien aus Gläsern / Containern zu laden.
  • Pfad: Ein Pfad ist im Grunde eine Zeichenfolge. Es verfügt jedoch über einige praktische Funktionen zum Verketten mehrerer Zeichenfolgen oder zum Hinzufügen von Dateien zu einer Zeichenfolge. Es stellt sicher, dass der Pfad, den Sie erstellen, gültig ist.
  • Datei: Dies ist ein Verweis auf ein Verzeichnis oder eine Datei. Es wird verwendet, um Dateien zu ändern, sie zu öffnen usw.

Es wäre einfacher, wenn sie zu einer Klasse zusammengefasst würden - sie sind wirklich verwirrend: D.

Ich hoffe das hilft dir :)

(Ich habe mir gerade die Dokumentation angesehen - siehe docs.oracle.com)

Cyphrags
quelle
0

Eine Datei ist eine abstrakte Darstellung einer Entität im lokalen Dateisystem.

Ein Pfad ist im Allgemeinen eine Zeichenfolge, die den Speicherort einer Datei innerhalb eines Dateisystems angibt. Der Dateiname ist normalerweise nicht enthalten. C: \ documents \ mystuff \ stuff.txt hätte also einen Pfad mit dem Wert "C: \ documents \ mystuff". Offensichtlich würde das Format der absoluten Dateinamen und Pfade von Dateisystem zu Dateisystem enorm variieren.

URL ist ein Susbset von URI, wobei URL normalerweise Ressourcen darstellt, auf die über http zugegriffen werden kann. Ich glaube nicht, dass es irgendeine ironclad Regel gibt, wann etwas eine URI gegen eine URL sein muss. URIs sind Zeichenfolgen in Form von "protocol: // resource-identifier" wie bitcoin: // params, http://something.com?param=value . Klassen wie URL umschließen im Allgemeinen die Zeichenfolge und stellen Dienstprogrammmethoden bereit, für die String keinen Grund zur Angabe hätte.

Keine Ressource, zumindest nicht in dem Sinne, von dem Sie sprechen. Nur weil eine Methode getResource heißt, heißt das nicht, dass sie ein Objekt vom Typ Resource zurückgibt.

Der beste Weg, um herauszufinden, was die Methoden einer Klasse tun, besteht darin, eine Instanz davon in Ihrem Code zu erstellen, die Methoden aufzurufen und dann entweder im Debug-Modus durchzugehen oder die Ergebnisse an System.out zu senden.

Jim W.
quelle
Ihre Definition von "Pfad" entspricht NICHT dem Konzept von "Pfad" im OP-Kontext
leonbloy