TLDR: записи jar не являются файлами.
Файл jar - это файл - примечание «a» означает «один».JAR-файл обычно создается путем взятия нескольких файлов (часто до сотен, тысяч или более), обычно, по крайней мере, некоторые из них являются файлами классов Java (скомпилированных), (обычно) сжимая данные из каждого и записывая (сжатые данные и имя для каждого файла в виде записи в банке.Однако возможно, что запись в банке не пришла из файла;например, запись манифеста часто создается «в поле», а не читается из файла, а для подписанного фляги всегда есть записи подписи.Но даже для записей jar, которые создаются из файлов, сами записи jar являются , а не файлами, и к ним нельзя получить доступ как к файлам с использованием базового доступа к файлам перед NIO.
У вас есть три варианта.
- Для jar в пути к классам - что, очевидно, ваш jar, поскольку вы нашли его как источник для загруженного класса,
ClassLoader
позволяет читать любую запись как «ресурс».Обычно он используется для таких вещей, как изображения, аудио, видео или другие данные, упакованные в банку с приложением, но он работает с записями, которые являются файлами классов.
// you can invoke it based on a known class like
InputStream is = Main.class.getResourceAsStream("path/for/package/Foo.class");
// or globally
InputStream is = ClassLoader.getResourceAsStream("path/for/package/Foo.class");
jar-файлы на самом деле являются zip-файлами «снизу», и Java уже давно позволяет вам получать доступ к zip-файлам, используя java.io.ZipFile
(напрямую) или java.io.ZipInputStream
(наслоение на FileInputStream
).Первый позволяет получить доступ к записям «случайным образом» с помощью так называемого центрального каталога, тогда как второй требует, чтобы вы обращались к записям в порядке их появления в файле (и работает с неисследуемыми базовыми формами файлов, такими как каналы и соединения с сокетами, но выздесь это не нужно), что делает его немного менее удобным для вашей цели, но все же работоспособным.См. Javadoc.
NIO в Java 7 и выше (и почти все должны быть там сейчас) добавляет поддержку альтернативных файловых систем, которые предоставляют файловую (или, по крайней мере, потоковую)как) доступ к вещам, отличным от реальных файлов, поддерживаемых базовой операционной системой или ее файловой системой (-ами).И хотя может быть добавлено еще больше, он поставляется с одним уже установленным альтернативным провайдером, который обрабатывает файлы jar (на самом деле почтовые индексы) - так, как вы хотите.
String jarname = Main.class.getProtectionDomain().getCodeSource().getLocation().getPath();
FileSystem fs = FileSystems.newFileSystem(Paths.get(jarname), null);
InputStream is = Files.newInputStream(fs.getPath("package/Foo.class"));
Обратите внимание, что во всех случаях я открыл InputStream, а не Reader (или Scanner).Считыватель и сканер предназначены для текста, состоящего из символов, и в большинстве случаев строк (которые по определению содержат символы).Файлы классов имеют некоторые символы здесь и там, но в основном это не символы и, следовательно, не текст;они должны быть прочитаны и обработаны как двоичные (с несколькими частями, которые при желании преобразуются в символы).Веселитесь.