В чем разница между ресурсом, 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 и Resource to File ? Мне кажется, что они должны быть одинаковыми, соответственно ...

Разница между 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объект; почему недостаточно Resource ( URL)? (А есть ли объект ресурса?)

Извините, если этот вопрос немного неорганизован; это просто отражает мою путаницу ... :)

Христианин
источник
5
А вы даже не начали смотреть на Path
Файловую Систему
2
@eckes По одной головной боли, пожалуйста. ;)
Christian
1
Ну, в контексте вашего вопроса File / URL + URI не связаны. Один - это средство для именования файлов и работы с ними, а другой - для именования и чтения из ресурсов (которые могут быть файлами). Методы getFile и getPath имеют дело с компонентами URL-адреса, которые (что сбивает с толку) названы как файловые объекты. Ресурсы загрузчика классов не представлены в виде файлов, поскольку они могут иметь разное происхождение (или быть вложенными в файлы JAR).
eckes 08
1
Отмечу, что этот код вряд ли будет работать по задумке. URLЯвляется непрозрачным - как показать это jar:file:, то есть ресурс в .jarархиве. Врезание этого в a Fileвряд ли приведет к чему-нибудь полезному.
Паук Борис
1
Суть вашей проблемы в том, что слова ресурс и путь могут иметь разное значение в зависимости от контекста.
Raedwald

Ответы:

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.

А есть ли ресурсный объект?

С точки зрения JRE, это просто термин. Некоторые фреймворки предоставляют вам такой класс (например, Spring Resource ).

Павел Горал
источник
5
Также существует java.nio.file.Path, по сути, замена (Java 7+) java.io.File, поскольку последний API был явно плохо продуман в первые дни Java.
ntoskrnl
1
Как правило, вам следует минимизировать использование URL-адресов, если в этом нет крайней необходимости. Причина в том, что методы equals и hashCode в URL реализованы удивительным образом: они блокируют вызовы методов.
kibibyte
3
@kibibyte: я бы ожидал, что вызов будет блокирующим, чтобы иметь асинхронную реализацию хэш-кода и равенства, что было бы очень тревожно. Я думаю, вы имели в виду, что вызовы будут пытаться разрешить хосту определить, эквивалентны ли они, и, следовательно, потенциально могут блокировать сетевые вызовы.
Newtopian
52

Я сейчас полностью запутался - в основном из-за терминологии, наверное. Может ли кто-нибудь рассказать мне о различиях или дать несколько ссылок на материалы, защищающие от пустышек? Особенно URI для URL и Resource to File? Мне кажется, что они должны быть одинаковыми, соответственно ...

Терминология сбивает с толку и иногда сбивает с толку, и в основном она родилась в результате эволюции 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 представляет ресурс, доступный через собственную файловую систему платформы . Он содержит только имя файла, поэтому на самом деле это скорее путь (см. Ниже), который платформа хоста интерпретирует в соответствии со своими собственными настройками, правилами и синтаксисом.

Обратите внимание, что File не должен указывать на что-то локальное , просто на то, что хост-платформа понимает в контексте доступа к файлу, например, путь UNC в Windows. Если вы смонтируете ZIP-файл в качестве файловой системы в своей ОС, тогда File будет нормально читать содержащиеся в нем записи.

URL (java.net, 1.0)

URL-адрес класса представляет собой унифицированный указатель ресурса, указатель на «ресурс» во всемирной паутине. Ресурс может быть чем-то таким же простым, как файл или каталог, или может быть ссылкой на более сложный объект, например запрос к базе данных или поисковой системе.

В тандеме с концепцией ресурса URL-адрес представляет этот ресурс так же, как класс File представляет файл на платформе хоста: как структурированная строка, указывающая на ресурс. URL дополнительно содержит схему, которая намекает на то, как добраться до ресурса (где «file:» означает «запросить платформу хоста»), и поэтому позволяет указывать на ресурсы через HTTP, FTP, внутри JAR и так далее.

К сожалению, URL-адреса имеют собственный синтаксис и терминологию, включая использование «файла» и «пути». В случае, если URL-адрес является URL-адресом файла, URL.getFile вернет строку, идентичную строке пути указанного файла.

Class.getResource возвращает URL: он более гибкий, чем возврат File, и удовлетворяет потребности системы, как это предполагалось в начале 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 и является частью New IO File API . Если File обязательно указывает на «файл» в понимании хост-платформы, Path является более общим: он представляет файл (ресурс) в произвольной файловой системе.

Путь устраняет зависимость от концепции файла на платформе хоста. Это может быть запись в ZIP-файле, файл, доступный через FTP или SSH-FS, представление пути к классам приложения с несколькими корнями или что угодно, что может быть осмысленно представлено через интерфейс FileSystem и его драйвер FileSystemProvider. Он дает возможность «монтировать» файловые системы в контексте приложения Java.

Платформа хоста представлена ​​через «файловую систему по умолчанию»; при вызове File.toPathвы получаете Path в файловой системе по умолчанию.


Теперь, если у меня есть локатор, который ссылается на класс или пакет в файле jar, будут ли эти два (т.е. путь к строкам файла) отличаться?

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

Наконец - и самое главное - зачем мне нужен объект File; почему недостаточно ресурса (URL)?

URL-адреса может быть недостаточно, потому что File дает вам доступ к служебным данным, таким как разрешения (для чтения, записи, исполняемого файла), тип файла (я каталог?) И возможность поиска и управления локальной файловой системой. Если эти функции вам нужны, их предоставят Файл или Путь.

Вам не нужен файл, если у вас есть доступ к пути. Однако для некоторых старых API может потребоваться File.

(А есть ли объект ресурса?)

Нет, нет. Таких названий много, но они не являются ресурсом в смысле ClassLoader.getResource.

JvR
источник
Вау, очень тщательно. Просто прохожу через это, но у вас уже есть первый последующий вопрос: когда вы говорите, что файл «содержит только имя файла», не противоречите ли вы своему первоначальному утверждению, что это «абстрактное представление путей к файлам и каталогам» - ие больше?
Christian
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:», так что они тоже, я бы сказал, что-то вроде «скрипта».

И локально: ресурс, путь и файлы

  • Ресурс: Ресурсы - это файлы внутри вашей банки. Они используются для загрузки файлов из jar / контейнеров.
  • Путь: Путь - это в основном строка. Но в нем есть несколько удобных функций для объединения нескольких строк или добавления файлов в строку. Это гарантирует, что путь, который вы строите, действителен.
  • Файл: это ссылка на каталог или файл. Он используется для изменения файлов, их открытия и т. Д.

Было бы проще, если бы они были объединены в один класс - они действительно сбивают с толку: D

Я надеюсь, это поможет вам :)

(Я только что посмотрел документацию - посмотрите на docs.oracle.com)

Cyphrags
источник
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 не имеет смысла предоставлять.

Нет такой вещи, как ресурс, по крайней мере, в том смысле, о котором вы говорите. То, что метод назван getResource, не означает, что он возвращает объект типа Resource.

В конечном итоге лучший способ выяснить, что делают методы класса, - это создать его экземпляр в вашем коде, вызвать методы и затем либо перейти в режим отладки, либо отправить результаты в System.out.

Джим В
источник
Ваше определение «пути» НЕ соответствует концепции «пути» в контексте OP
leonbloy