Jaka jest różnica między zasobem, identyfikatorem URI, adresem URL, ścieżką i plikiem w języku Java?


96

Patrzę teraz na fragment kodu Java, który przyjmuje ścieżkę jako ciąg i pobiera jego adres URL za pomocą URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);, a następnie wywołuje String path = resource.getPath()i ostatecznie wykonuje new File(path);.

Aha, i są też wezwania do URL url = resource.toURI();i String file = resource.getFile().

Jestem teraz całkowicie zdezorientowany - myślę, że głównie z powodu terminologii. Czy ktoś może przeprowadzić mnie przez różnice lub podać kilka linków do materiałów odpornych na atrapy? Zwłaszcza URI do adresu URL i zasobu do pliku ? Wydaje mi się, że powinny być odpowiednio tym samym ...

Różnica między getFile()i getPath()jest wyjaśniona tutaj: Jaka jest różnica między url.getFile () a getpath ()? (Co ciekawe, obaj wydają się zwracać Strings, co prawdopodobnie bardzo poprawia mój stan umysłu ...)

Jeśli mam lokalizator, który odwołuje się do klasy lub pakietu w pliku jar, czy te dwa elementy (tj. Ścieżka i ciągi plików) będą się różnić?

resource.toString()dałby ci w jar:file:/C:/path/to/my.jar!/com/example/końcu (zwróć uwagę na wykrzyknik).

Czy różnica między identyfikatorem URI i adresem URL w Javie polega na tym, że ten pierwszy nie koduje spacji? Por. Pliki, identyfikatory URI i adresy URL są w konflikcie w Javie (ta odpowiedź dość dobrze wyjaśnia ogólną, koncepcyjną różnicę między tymi dwoma terminami: identyfikatory URI i lokalizowanie adresów URL; )

Wreszcie - i najważniejsze - po co mi Fileprzedmiot; dlaczego Resource ( URL) nie jest wystarczające? (A czy istnieje obiekt zasobów?)

Przepraszamy, jeśli to pytanie jest trochę niezorganizowane; to po prostu odzwierciedla zamieszanie, które mam ... :)


5
I nawet nie zacząłeś patrzeć na PathFileSystem z NIO :)
eckes

2
@eckes Jeden ból głowy na raz, proszę. ;)
Christian

1
Cóż, w kontekście twojego pytania Plik / URL + URI nie są powiązane. Jeden służy do nazywania i operowania na plikach, a drugi do nazywania i odczytywania zasobów (którymi mogą być pliki). Metody getFile i getPath zajmują się składnikami adresu URL, które są (myląco) nazwane jak obiekty plikowe. Zasoby modułu ładującego klasy nie są reprezentowane jako pliki, ponieważ mogą mieć różne pochodzenie (lub być zagnieżdżone w plikach JAR).
eckes

1
Chciałbym zauważyć, że ten kod prawdopodobnie nie zadziała zgodnie z przeznaczeniem. A URLjest nieprzezroczysty - jak pokazujesz jar:file:, czyli zasób w .jararchiwum. Kolosalny że w Filejest bardzo mało prawdopodobne, aby doprowadzić do niczego użytecznego.
Boris the Spider

1
Sednem twojego problemu jest to, że słowa zasób i ścieżka mogą mieć różne znaczenia, w zależności od kontekstu.
Raedwald

Odpowiedzi:


43

UPDATE 12.04.2017 Sprawdź odpowiedź JvR, ponieważ zawiera bardziej wyczerpujące i dokładne wyjaśnienie!


Zwróć uwagę, że nie uważam się za w 100% kompetentnego do udzielenia odpowiedzi, ale mimo to oto kilka uwag:

  • File reprezentuje plik lub katalog dostępny za pośrednictwem systemu plików
  • zasób to ogólny termin określający obiekt danych, który może być ładowany przez aplikację
    • zazwyczaj zasoby to pliki dystrybuowane z aplikacją / biblioteką i ładowane przez mechanizm ładowania klas (gdy znajdują się na ścieżce klasy)
  • URL#getPathpobiera w części ścieżki adresu URL ( protocol://host/path?query)
  • URL#getFile zgodnie ze zwrotami JavaDoc path+query

W Javie URIto tylko struktura danych służąca do manipulowania samym identyfikatorem ogólnym.

URLz drugiej strony jest tak naprawdę lokalizatorem zasobów i oferuje funkcje umożliwiające rzeczywiste odczytywanie zasobów za pośrednictwem zarejestrowanych URLStreamHandleradresów.

Adresy URL mogą prowadzić do zasobów systemu plików i można utworzyć adres URL dla każdego zasobu systemu plików przy użyciu file://protokołu (stąd relacja File<-> URL).

Należy również pamiętać, że URL#getFilenie ma to związku z java.io.File.


Dlaczego potrzebuję obiektu File; dlaczego zasób (adres URL) nie jest wystarczający?

Wystarczy. Tylko jeśli chcesz przekazać zasób do jakiegoś komponentu, który może pracować tylko z plikami, musisz go pobrać File. Jednak nie wszystkie adresy URL zasobów można przekonwertować na adresy File.

Czy istnieje obiekt zasobu?

Z punktu widzenia środowiska JRE to tylko termin. Niektóre frameworki zapewniają taką klasę (np . Zasoby Springa ).


5
Jest też java.nio.file.Path, co jest w zasadzie zamiennikiem (Java 7+) java.io.File, ponieważ ten drugi interfejs API był najwyraźniej słabo przemyślany we wczesnych latach Java.
ntoskrnl

1
Ogólnie rzecz biorąc, należy zminimalizować użycie adresu URL, chyba że jest to absolutnie potrzebne. Powodem jest to, że metody equals i hashCode adresu URL są zaimplementowane w zaskakujący sposób: blokują wywołania metod.
kibibyte

3
@kibibyte: Spodziewałbym się, że wywołanie będzie blokować, mieć asynchroniczną implementację hashcode i jest teraz równe, co byłoby bardzo niepokojące. Myślę, że chodziło Ci o to, że wywołania będą próbowały rozwiązać hosta, aby znaleźć, czy są równoważne, a tym samym mogą potencjalnie blokować połączenia sieciowe.
Newtopian

52

Jestem teraz całkowicie zdezorientowany - myślę, że głównie z powodu terminologii. Czy ktoś może przeprowadzić mnie przez różnice lub podać kilka linków do materiałów odpornych na atrapy? Zwłaszcza URI do adresu URL i zasobu do pliku? Wydaje mi się, że powinny być odpowiednio tym samym ...

Terminologia jest zagmatwana i czasami dezorientująca, a w większości zrodziła się z ewolucji języka Java jako interfejsu API i platformy w czasie. Aby zrozumieć, jak te terminy zaczęły oznaczać to, co robią, ważne jest, aby rozpoznać dwie rzeczy, które wpływają na projekt Javy:

  • Kompatybilność wsteczna. Stare aplikacje powinny działać na nowszych instalacjach, najlepiej bez modyfikacji. Oznacza to, że stary interfejs API (z jego nazwami i terminologią) musi być obsługiwany przez wszystkie nowsze wersje.
  • Wieloplatformowy. Interfejs API powinien zapewniać użyteczną abstrakcję swojej platformy bazowej, niezależnie od tego, czy jest to system operacyjny, czy przeglądarka.

Przedstawię koncepcje i wyjaśnię, jak powstały. Odpowiem potem na inne, konkretne pytania, bo być może będę musiał odnieść się do czegoś w pierwszej części.

Co to jest „zasób”?

Abstrakcyjny, ogólny fragment danych, który można zlokalizować i odczytać. Mówiąc wprost, Java używa tego do odniesienia się do „pliku”, który może nie być plikiem, ale reprezentuje nazwany fragment danych. Nie ma bezpośredniej reprezentacji klasy lub interfejsu w Javie , ale ze względu na swoje właściwości (lokalizowalny, czytelny) jest często reprezentowany przez adres URL.

Ponieważ jednym z wczesnych celów projektowania Javy było uruchomienie w przeglądarce, jako aplikacji piaskownicy (apletów!) Z bardzo ograniczonymi prawami / przywilejami / poświadczeniem bezpieczeństwa, Java czyni wyraźną (teoretyczną) różnicę między plikiem (czymś w lokalnym system plików) i zasób (coś, co musi przeczytać). Dlatego odczytywanie czegoś odnoszącego się do aplikacji (ikon, plików klas itp.) Odbywa się za ClassLoader.getResourcepośrednictwem klasy File, a nie.

Niestety, ponieważ „zasób” jest również użytecznym terminem ogólnym poza tą interpretacją, jest również używany do nazywania bardzo konkretnych rzeczy (np. Klasy ResourceBundle , UIResource , Resource ), które w tym sensie nie są zasobami.

Główne klasy reprezentujące (ścieżka do) zasób to java.nio.file.Path , java.io.File , java.net.URI i java.net.URL .

Plik (java.io, 1.0)

Abstrakcyjna reprezentacja nazw ścieżek do plików i katalogów.

Klasa File reprezentuje zasób, do którego można uzyskać dostęp za pośrednictwem natywnego systemu plików platformy . Zawiera tylko nazwę pliku, więc jest to bardziej ścieżka (patrz dalej), którą platforma hosta interpretuje zgodnie z własnymi ustawieniami, regułami i składnią.

Zwróć uwagę, że plik nie musi wskazywać czegoś lokalnego , tylko coś, co platforma hosta rozumie w kontekście dostępu do pliku, np. Ścieżka UNC w systemie Windows. Jeśli zamontujesz plik ZIP jako system plików w swoim systemie operacyjnym, plik odczyta zawarte w nim wpisy dobrze.

URL (java.net, 1.0)

Adres URL klasy reprezentuje Uniform Resource Locator, czyli wskaźnik do „zasobu” w sieci WWW. Zasobem może być coś tak prostego, jak plik lub katalog, lub może to być odniesienie do bardziej skomplikowanego obiektu, takiego jak zapytanie do bazy danych lub wyszukiwarki.

W połączeniu z pojęciem zasobu adres URL reprezentuje ten zasób w taki sam sposób, jak klasa File reprezentuje plik na platformie hosta: jako strukturalny ciąg, który wskazuje na zasób. URL dodatkowo zawiera schemat, który podpowiada jak dotrzeć do zasobu (gdzie „plik:” jest „zapytaj platformę hosta”), a więc umożliwia wskazywanie zasobów przez HTTP, FTP, wewnątrz JAR i tak dalej.

Niestety, adresy URL mają własną składnię i terminologię, w tym użycie „pliku” i „ścieżki”. W przypadku, gdy adres URL jest adresem URL pliku, URL.getFile zwróci ciąg identyczny z ciągiem ścieżki do pliku, do którego się odwołuje.

Class.getResource zwraca adres URL: jest bardziej elastyczny niż zwracanie pliku i spełnia wymagania systemu, jak to sobie wyobrażano na początku lat 90-tych.

URI (java.net, 1.4)

Reprezentuje odwołanie do Uniform Resource Identifier (URI).

URI to (niewielka) abstrakcja dotycząca adresu URL. Różnica między URI a URL jest koncepcyjna i głównie akademicka, ale URI jest lepiej zdefiniowany w sensie formalnym i obejmuje szerszy zakres przypadków użycia. Ponieważ adresy URL i URI nie są tym samym, wprowadzono nową klasę, która je reprezentuje, z metodami URI.toURL i URL.toURI do poruszania się między nimi.

W Javie główna różnica między adresem URL a URI polega na tym, że adres URL niesie oczekiwanie, że będzie można go rozwiązać , czyli coś, z czego aplikacja może chcieć uzyskać strumień wejściowy; identyfikator URI jest traktowany bardziej jak abstrakcyjna rzecz, która może wskazywać na coś, co można rozwiązać (i zwykle tak jest), ale to, co oznacza i jak do niego dotrzeć, jest bardziej otwarte na kontekst i interpretację.

Ścieżka (java.nio.file, 1.7)

Obiekt, którego można użyć do zlokalizowania pliku w systemie plików. Zwykle będzie reprezentować ścieżkę pliku zależną od systemu.

Nowy interfejs API plików, oznaczony ikoną w interfejsie Path, zapewnia znacznie większą elastyczność niż może zaoferować klasa File. Interfejs Path jest abstrakcją klasy File i jest częścią interfejsu API New IO File . Tam, gdzie plik koniecznie wskazuje na „plik” w rozumieniu platformy hosta, ścieżka jest bardziej ogólna: reprezentuje plik (zasób) w dowolnym systemie plików.

Ścieżka eliminuje zależność od koncepcji pliku platformy hosta. Może to być wpis w pliku ZIP, plik dostępny przez FTP lub SSH-FS, reprezentacja ścieżki klas aplikacji z wieloma korzeniami lub tak naprawdę wszystko, co można w znaczący sposób przedstawić za pomocą interfejsu FileSystem i jego sterownika, FileSystemProvider. Wprowadza moc „montowania” systemów plików w kontekście aplikacji Java.

Platforma hosta jest reprezentowana przez „domyślny system plików”; kiedy dzwonisz File.toPath, otrzymasz ścieżkę w domyślnym systemie plików.


Jeśli mam lokalizator, który odwołuje się do klasy lub pakietu w pliku jar, czy te dwa elementy (tj. Ścieżka i ciągi plików) będą się różnić?

Mało prawdopodobne. Jeśli plik jar jest na lokalnym systemie plików, nie powinien mieć element zapytania, tak URL.getPathi URL.getFilepowinien zwrócić ten sam rezultat. Jednak wybierz ten, którego potrzebujesz: adresy URL plików mogą zazwyczaj nie zawierać składników zapytania, ale i tak mógłbym je dodać.

Wreszcie - i co najważniejsze - dlaczego potrzebuję obiektu File; dlaczego zasób (adres URL) nie jest wystarczający?

Adres URL może nie wystarczyć, ponieważ plik zapewnia dostęp do danych porządkowych, takich jak uprawnienia (do odczytu, zapisu, wykonywania), typ pliku (czy jestem katalogiem?) Oraz możliwość wyszukiwania i manipulowania lokalnym systemem plików. Jeśli potrzebujesz tych funkcji, podaj je w pliku lub ścieżce.

Nie potrzebujesz pliku, jeśli masz dostęp do ścieżki. Jednak niektóre starsze API mogą wymagać pliku.

(A czy istnieje obiekt zasobów?)

Nie, nie ma. Jest wiele takich rzeczy, które się tak nazywają, ale nie są one zasobami w sensie ClassLoader.getResource.


Wow, bardzo dokładne. Właśnie przechodzę przez to, ale już mam pierwsze pytanie uzupełniające: Kiedy mówisz, że plik „zawiera tylko nazwę pliku”, nie zaprzeczaj swojemu początkowemu stwierdzeniu, że jest to „abstrakcyjna reprezentacja nazw ścieżek do plików i katalogów” - iemore?
Christian

1
@Christian Miałem na myśli „tylko nazwę”, ponieważ: w żaden sposób nie modeluje zawartości pliku; to tylko cienka owijka wokół sznurka. Część „abstrakcyjna reprezentacja” jest cytowana z dokumentacji API. ;)
JvR

Ta odpowiedź zasługuje na znacznie więcej głosów pozytywnych ... zaktualizuje moją zaakceptowaną odpowiedź, aby skierować czytelników do tej.
Pavel Horal,

12

Odpowiedź Pavela Horala jest miła.

Jak mówi, słowo „plik” ma zupełnie inne (praktycznie niepowiązane) znaczenia w URL#getFilevs java.io.File- może to część zamieszania.

Wystarczy dodać:

  • Zasobów w Javie jest pojęciem abstrakcyjnym, źródło danych, które mogą być odczytane. Lokalizacja (lub adres) zasobu jest reprezentowana w języku Java przez URLobiekt.

  • Zasób może odpowiadać zwykłego pliku w lokalnym systemie plików (szczególnie, gdy jej URLzaczyna file://). Ale zasób jest bardziej ogólny (może to być również jakiś plik przechowywany w słoiku lub jakieś dane do odczytania z sieci, z pamięci lub ...). Jest to również bardziej ograniczone, ponieważ File(oprócz tego, że jest czymś innym niż zwykły plik: katalog, link) można również utworzyć i zapisać.

  • Pamiętaj, że w Javie Fileobiekt tak naprawdę nie reprezentuje „pliku”, ale lokalizację (pełną nazwę ze ścieżką) pliku. Tak więc Fileobiekt umożliwia zlokalizowanie (i otwarcie) pliku, podobnie jak URLumożliwia dostęp (i otwieranie) do zasobu. (W ResourceJavie nie ma klasy, która reprezentowałaby zasób, ale nie ma też klasy, która reprezentowałaby plik! Raz jeszcze: Filenie jest plikiem, to ścieżka do pliku).


3

Jak je rozumiem, możesz je podzielić na następujące kategorie:

Oparte na sieci: identyfikatory URI i adresy URL.

  • Adresy URL: adres URL to określona lokalizacja w Internecie (zwykły adres internetowy, taki jak - stackoverflow.com)
  • URI: Ever URL to URI. Ale identyfikatory URI mogą również zawierać rzeczy takie jak „mailto:”, więc są one także, cóż, powiedziałbym, że to „skrypt”.

I lokalnie: zasoby, ścieżki i pliki

  • Zasoby: zasoby to pliki w twoim słoiku. Służą do ładowania plików z słoików / kontenerów.
  • Ścieżka: ścieżka jest w zasadzie ciągiem. Ale zawiera kilka przydatnych funkcji do łączenia wielu ciągów lub dodawania plików do ciągu. Daje pewność, że ścieżka, którą budujesz, jest prawidłowa.
  • Plik: jest to odniesienie do katalogu lub pliku. Służy do modyfikowania plików, otwierania ich itp.

Byłoby łatwiej, gdyby zostały połączone w jedną klasę - są naprawdę zagmatwane: D

Mam nadzieję, że to Ci pomoże :)

(Właśnie przejrzałem dokumentację - zajrzyj na docs.oracle.com)


0

Plik jest abstrakcyjną reprezentacją jednostki w lokalnym systemie plików.

Ścieżka to zazwyczaj ciąg znaków wskazujący lokalizację pliku w systemie plików. Zwykle nie zawiera nazwy pliku. Więc c: \ documents \ mystuff \ stuff.txt miałoby ścieżkę o wartości „C: \ documents \ mystuff”. Oczywiście format bezwzględnych nazw plików i ścieżek różni się znacznie w zależności od systemu plików.

URL to zestaw identyfikatorów URI z adresem URL zwykle reprezentującym zasoby dostępne przez http. Nie sądzę, aby istniała jakaś żelazna zasada dotycząca tego, kiedy coś musi być identyfikatorem URI, a nie adresem URL. Identyfikatory URI to ciągi znaków w postaci „protokół: // identyfikator-zasobu”, na przykład bitcoin: // params, http://something.com?param=value . Klasy takie jak URL zazwyczaj zawijają ciąg i dostarczają metody narzędziowe, których String nie miałby powodu podawać.

Nie ma czegoś takiego jak Zasoby, przynajmniej nie w tym sensie, o którym mówisz. To, że metoda nosi nazwę getResource, nie oznacza, że ​​zwraca ona obiekt typu Resource.

Ostatecznie najlepszym sposobem, aby dowiedzieć się, co robią metody klasy, jest utworzenie jej instancji w kodzie, wywołanie metod, a następnie przejście przez tryb debugowania lub wysłanie wyników do System.out.


Twoja definicja „ścieżki” NIE odpowiada pojęciu „ścieżki” w kontekście OP
leonbloy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.