Яка різниця між ресурсом, URI, URL-адресою, шляхом та файлом у Java?


96

Я дивлюсь на шматок коду 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 ()? (Цікаво, що вони обидва повертають рядки, що, мабуть, багато додає до мого душевного стану ...)

Тепер, якщо у мене є локатор, який посилається на клас або пакет у jar-файлі, чи будуть ці два (тобто шлях до рядків файлів) відрізнятися?

resource.toString()jar:file:/C:/path/to/my.jar!/com/example/зрештою дав би вам (зверніть увагу на знак оклику).

Чи є різниця між URI та URL-адресою в Java те, що перший не кодує пробіли? Пор. Файли, URI та URL-адреси конфліктують у Java (Ця відповідь досить добре пояснює загальну, концептуальну різницю між цими двома термінами: URI ідентифікують та знаходять URL-адреси; )

Нарешті - і найголовніше - навіщо мені Fileпредмет? чому ресурсу ( URL) недостатньо? (А чи є об’єкт Resource?)

Вибачте, якщо це питання трохи неорганізоване; це просто відображає мою плутанину ... :)


5
І ви навіть не почали дивитися на PathFileSystem від NIO :)
еккес

2
@eckes Будь ласка, один головний біль за раз. ;)
Крістіан

1
У контексті вашого запитання Файл / URL + URI не пов'язані. Один із них - це засіб для іменування файлів та оперування ними, інший - метод для іменування та читання з ресурсів (які можуть бути файлами). Методи getFile та getPath мають справу з компонентами URL-адреси, які (заплутано) називаються як файлові об'єкти. Ресурси Classloader не представлені у вигляді файлів, оскільки вони можуть мати різне походження (або бути вкладеними у файли JAR).
eckes

1
Я б зазначив, що цей код навряд чи буде працювати належним чином. URLЄ непрозорим - як показати це jar:file:, тобто ресурс в .jarархіві. Взлом цього в a Fileнавряд чи призведе до чогось корисного.
Павук Борис

1
Суть вашої проблеми полягає в тому, що слова ресурс і шлях можуть мати різне значення, залежно від контексту.
Редвальд,

Відповіді:


43

ОНОВИТИ 2017-04-12 Перевірте відповідь JvR, оскільки вона містить більш вичерпні та точні пояснення!


Зверніть увагу, що я не вважаю себе на 100% компетентним відповідати, але тим не менш є кілька коментарів:

  • File представляє файл або каталог, доступний через файлову систему
  • Ресурс - це загальний термін для об'єкта даних, який може завантажувати програма
    • зазвичай ресурси - це файли, що розподіляються разом із додатком / бібліотекою та завантажуються за допомогою механізму завантаження класу (коли вони знаходяться на шляху до класу)
  • URL#getPathотримує на частині шляху URL ( protocol://host/path?query)
  • URL#getFile відповідно до повернення JavaDoc path+query

У Java - URIце просто структура даних для маніпулювання самим загальним ідентифікатором.

URLз іншого боку, насправді є локатором ресурсів і пропонує вам функції для фактичного читання ресурсу через зареєстровані URLStreamHandlers.

URL-адреси можуть вести до ресурсів файлової системи, і ви можете побудувати URL-адресу для кожного ресурсу файлової системи, використовуючи file://протокол (отже, відношення File<-> URL).

Також пам’ятайте, що URL#getFileце не пов’язано з java.io.File.


Навіщо мені об'єкт File; чому недостатньо ресурсу (URL)?

Цього достатньо. Тільки якщо ви хочете передати ресурс якомусь компоненту, який може працювати лише з файлами, вам потрібно отримати Fileз нього. Однак не всі URL-адреси ресурсів можна перетворити на Files.

І чи є об’єкт Resource?

З точки зору JRE, це просто термін. Деякі фреймворки надають вам такий клас (наприклад, Spring's Resource ).


5
Є також java.nio.file.Path, що в основному є заміною (Java 7+) java.io.File, оскільки останній API, мабуть, був погано продуманий на початку Java.
ntoskrnl

1
Як правило, слід мінімізувати використання URL-адрес, якщо це не є абсолютно необхідним. Причина полягає в тому, що URL-адреси equals і hashCode реалізовані дивовижно: вони блокують виклики методів.
кібібайт

3
@kibibyte: Я би очікував, що дзвінок буде блокувати, мати асинхронну реалізацію хеш-коду і рівних зараз, що буде дуже тривожно. Я думаю, що ви мали на увазі, що дзвінки намагатимуться вирішити хосту, щоб знайти, чи є вони еквівалентними, і, отже, потенційно можуть блокувати дзвінки в мережі.
Ньютопіан,

50

Зараз я абсолютно розгублений - я думаю, здебільшого через термінологію. Хтось може, будь ласка, провести мене через розбіжності або надати кілька посилань на матеріал, що захищає від манекена? Особливо URI до URL-адреси та ресурсу до файлу? Для мене здається, що вони повинні бути одним і тим же, відповідно ...

Термінологія заплутана і іноді бентежить і в основному породжена еволюцією Java як API та як платформи з часом. Щоб зрозуміти, як ці терміни означали те, що вони роблять, важливо визнати дві речі, які впливають на дизайн Java:

  • Зворотна сумісність. Старі програми повинні працювати на нових установках, в ідеалі без змін. Це означає, що старий API (з його назвами та термінологією) потрібно підтримувати у всіх новіших версіях.
  • Крос-платформа. API повинен забезпечувати корисну абстракцію базової платформи, будь то операційна система чи браузер.

Я пройдусь по концепціях і тому, як вони виникли. Після цього я відповім на інші Ваші конкретні запитання, оскільки, можливо, мені доведеться звернутися до чогось у першій частині.

Що таке "ресурс"?

Абстрактна загальна інформація, яку можна знайти та прочитати. Помилково кажучи, Java використовує це для позначення "файлу", який може не бути файлом, але представляє іменований фрагмент даних. Він не має прямого представлення класу чи інтерфейсу в Java , але через свої властивості (доступний для читання) він часто представлений URL-адресою.

Оскільки однією з перших цілей Java було розробити всередині браузера, як ізольовану програму (аплети!) З дуже обмеженими правами / привілеями / дозволом безпеки, Java робить чітку (теоретичну) різницю між файлом (щось на локальному файлова система) та ресурс (те, що йому потрібно прочитати). Ось чому читання чогось щодо програми (піктограм, файлів класів тощо) виконується через, ClassLoader.getResourceа не через клас File.

На жаль, оскільки "ресурс" - це також корисний загальний термін поза цим тлумаченням, він також використовується для назви дуже конкретних речей (наприклад, класу ResourceBundle , UIResource , Resource ), які в цьому сенсі не є ресурсом.

Основними класами, що представляють (шлях до) ресурсу, є java.nio.file.Path , java.io.File , java.net.URI та java.net.URL .

Файл (java.io, 1.0)

Абстрактне представлення імен шляхів до файлів та каталогів.

Клас File представляє ресурс, доступний за допомогою власної файлової системи платформи . Він містить лише ім'я файлу, тому насправді це більше шлях (див. Пізніше), який платформа хоста інтерпретує відповідно до власних налаштувань, правил та синтаксису.

Зверніть увагу, що Файлу не потрібно вказувати на щось локальне , а лише на те, що платформа хоста розуміє в контексті доступу до файлів, наприклад, шлях UNC у Windows. Якщо ви змонтуєте файл ZIP як файлову систему у вашій ОС, тоді файл буде добре читати вміщені записи.

URL (java.net, 1.0)

URL-адреса класу представляє уніфікований локатор ресурсів, вказівник на "ресурс" у Всесвітній павутині. Ресурсом може бути щось настільки просте, як файл чи каталог, або може бути посиланням на більш складний об'єкт, наприклад, запит до бази даних або пошукової системи.

У тандемі з концепцією ресурсу URL-адреса представляє цей ресурс так само, як клас File представляє файл на хост-платформі: як структурований рядок, який вказує на ресурс. URL-адреса додатково містить схему, яка вказує на те, як отримати доступ до ресурсу (з "file:" being "ask the host platform"), і тому дозволяє вказувати на ресурси через HTTP, FTP, всередині JAR і багато іншого.

На жаль, URL-адреси мають власний синтаксис та термінологію, включаючи використання "файл" та "шлях". Якщо URL-адреса є URL-адресою файлу, URL.getFile поверне рядок, ідентичний рядку шляху посиланого файлу.

Class.getResource повертає URL-адресу: вона є гнучкішою, ніж повернення файлу, і вона задовольняє потреби системи, як це уявлялося на початку 1990-х.

URI (java.net, 1.4)

Представляє посилання на уніфікований ідентифікатор ресурсу (URI).

URI - це (незначна) абстракція над URL-адресою. Різниця між URI та URL є концептуальною та переважно академічною, але URI краще визначається у формальному розумінні та охоплює ширший спектр випадків використання. Оскільки URL та URI - це не одне і те ж, для їх представлення було введено новий клас із методами URI.toURL та URL.toURI для переміщення між одними та іншими.

У Java основна відмінність між URL та URI полягає в тому, що URL несе очікування, що його можна вирішити , від чого програма може захотіти InputStream; URI трактується більше як абстрактний річмаджідж, який може вказувати на щось вирішуване (і, як правило, це робить), але те, що він означає і як до нього дійти, є більш відкритим для контексту та інтерпретації.

Шлях (java.nio.file, 1.7)

Об'єкт, за допомогою якого можна знайти файл у файловій системі. Зазвичай він представлятиме системний шлях до файлу.

Новий файловий API, позначений у інтерфейсі Path, забезпечує набагато більшу гнучкість, ніж клас File. Інтерфейс Path є абстракцією класу File і є частиною API нового файлу IO . Там, де Файл обов’язково вказує на „файл”, як його розуміє хост-платформа, Path є більш загальним: він представляє файл (ресурс) у довільній файловій системі.

Шлях забирає опору на концепцію файлу хост-платформи. Це може бути запис у ZIP-файлі, файл, до якого можна отримати доступ за допомогою FTP або SSH-FS, багатокореневе представлення шляху до класу програми або насправді будь-що, що може бути значущим чином представлене через інтерфейс FileSystem та його драйвер FileSystemProvider. Це вводить силу "монтування" файлових систем у контекст програми Java.

Хост-платформа представлена ​​через "файлову систему за замовчуванням"; під час дзвінка File.toPathви отримуєте шлях до файлової системи за замовчуванням.


Тепер, якщо у мене є локатор, який посилається на клас або пакет у jar-файлі, чи будуть ці два (тобто шлях до рядків файлів) відрізнятися?

Навряд чи. Якщо файл банку знаходиться на локальній файловій системі, ви не повинні мати компонент запиту, так URL.getPathі URL.getFileповинен повертати один і той же результат. Однак виберіть той, який вам потрібен: URL-адреси файлів, як правило, не містять компонентів запиту, але я б міг впевнитись, що все одно додаю один.

Нарешті - і найголовніше - навіщо мені об’єкт File; чому недостатньо ресурсу (URL)?

URL-адреси може бути недостатньо, оскільки файл надає доступ до даних ведення домашнього господарства, таких як дозволи (доступні для читання, запис, виконуваний файл), тип файлу (я каталог?), А також можливість пошуку та керування локальною файловою системою. Якщо це функції, які вам потрібні, тоді надайте їх File або Path.

Вам не потрібен файл, якщо у вас є доступ до шляху. Деякі старі API можуть вимагати файлу.

(А чи є об’єкт Resource?)

Ні, немає. Є багато речей, що називаються подібними, але вони не є ресурсом у тому сенсі ClassLoader.getResource.


Ого, дуже ретельно. Просто проходжу це, але вже маю перше подальше запитання: Коли ви говорите, що файл "містить лише ім'я файлу", не суперечте своєму початковому твердженню, що це "абстрактне представлення імен шляхів до файлів і каталогів" - iemore?
Крістіан

1
@Christian Я мав на увазі "лише ім'я", як у: жодним чином не моделює вміст файлу; це просто тонка обгортка навколо струни. Частина "абстрактного подання" наведена в документах API. ;)
JvR

Ця відповідь заслуговує набагато більше голосів ... оновить мою прийняту відповідь, щоб вказати читачам на цю.
Павло Гораль

12

Відповідь Павла Гораля приємна.

Як він каже, слово "файл" має абсолютно різні (практично не пов'язані) значення в URL#getFilevs java.io.File- можливо, це частина плутанини.

Просто додати:

  • Ресурс в Java є абстрактним поняттям, джерело даних , який може бути прочитаний. Місцезнаходження (або адреса) ресурсу представлено в Java URLоб’єктом.

  • Ресурс може відповідати звичайному файлу в локальній файловій системі ( в Зокрема, коли його URLпочинається з file://). Але ресурс є більш загальним (це може бути також якийсь файл, що зберігається в банку, або деякі дані для зчитування з мережі, або з пам'яті, або ...). І це також більш обмежено, тому що File(крім інших речей, ніж звичайний файл: каталог, посилання), також можна створити та записати.

  • Пам'ятайте, в Java Fileоб'єкт насправді не представляє "файл", а місцезнаходження (повне ім'я із шляхом) файлу. Отже, Fileоб’єкт дозволяє знайти (і відкрити) файл, оскільки URLдозволяє отримати доступ (і відкрити) ресурс. (У ResourceJava немає класу, який би представляв ресурс, але не існує і такого, який би представляв файл! Ще раз: Fileце не файл, це шлях до файлу).


3

Наскільки я їх розумію, ви можете класифікувати їх наступним чином:

Інтернет: URI та URL-адреси.

  • URL-адреси: URL-адреса - це певне розташування на інтервалі (просто звичайний веб-адрес, наприклад - stackoverflow.com)
  • URI. Кожна URL-адреса - це URI. Але URI також можуть містити такі речі, як "mailto:", отже, вони теж є, ну, щось із "сценарію", я б сказав.

І місцеві: ресурс, шлях та файли

  • Ресурс: Ресурси - це файли всередині вашої банки. Вони використовуються для завантаження файлів з банок / контейнерів.
  • Шлях: Шлях - це в основному рядок. Але він має деякі зручні функції для об’єднання декількох рядків або додавання файлів до рядка. Це гарантує правильність шляху, який ви будуєте.
  • Файл: Це посилання на каталог або файл. Він використовується для модифікації файлів, їх відкриття тощо.

Було б простіше, якби їх об’єднали в один клас - вони справді заплутані: D

Сподіваюся, це вам допоможе :)

(Я щойно подивився документацію - подивіться на docs.oracle.com)


0

Файл - це абстрактне подання сутності в локальній файловій системі.

Шлях, як правило, являє собою рядок, що вказує місце розташування файлу у файловій системі. Зазвичай воно не включає ім’я файлу. Тож c: \ documents \ mystuff \ stuff.txt мав би шлях із значенням "C: \ documents \ mystuff". Очевидно, що формат абсолютних імен файлів та шляхів буде сильно відрізнятися від файлової системи до файлової системи.

URL - це набір URI, URL-адреса якого зазвичай представляє ресурси, доступні через http. Я не думаю, що існує якесь залізне правило про те, коли щось має бути URI проти URL-адреси. URI - це рядки у формі "протокол: // ідентифікатор ресурсу", такі як bitcoin: // params, http://something.com?param=value . Класи, такі як URL, зазвичай обертають рядок і надають корисні методи, які String не мав би підстав надавати.

Немає такого поняття, як Resource, принаймні не в тому сенсі, про який ви говорите. Те, що метод називається getResource, не означає, що він повертає об’єкт типу Resource.

Зрештою, найкращий спосіб зрозуміти, що роблять методи Класу, - це створити його екземпляр у своєму коді, викликати методи, а потім або перейти в режим налагодження, або надіслати результати до System.out.


Ваше визначення поняття "шлях" НЕ відповідає поняттю "шлях" у контексті OP
leonbloy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.