Как я могу перечислить файлы внутри файла JAR?
у меня есть этот код, который читает все файлы из каталога.
File textFolder = new File("text_directory");
File [] texFiles = textFolder.listFiles( new FileFilter() {
public boolean accept( File file ) {
return file.getName().endsWith(".txt");
}
});
Он отлично работает. Он заполняет массив всеми файлами, которые заканчиваются ".txt "из каталога "text_directory".
как я могу прочитать содержимое каталога подобным образом внутри файл JAR?
так что я действительно хочу сделать, чтобы перечислить все изображения внутри моего файла JAR, так что я могу загрузить их с:
ImageIO.read(this.getClass().getResource("CompanyLogo.png"));
(это работает, потому что "CompanyLogo "является" жестко закодированным", но количество изображений внутри файла JAR может быть от 10 до 200 переменной длины.)
EDIT
так что я думаю, моя главная проблема будет: как знать имя файла JAR где живет мой основной класс?
конечно, я мог бы прочитать его с помощью java.util.Zip.
моя структура выглядит так:
они так:
my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest
прямо сейчас я могу загрузить, например "images / image01.ПНГ" через:
ImageIO.read(this.getClass().getResource("images/image01.png));
но только потому, что я знаю имя файла, для остальных я должен загружать их динамически.
13 ответов:
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource(); if (src != null) { URL jar = src.getLocation(); ZipInputStream zip = new ZipInputStream(jar.openStream()); while(true) { ZipEntry e = zip.getNextEntry(); if (e == null) break; String name = e.getName(); if (name.startsWith("path/to/your/dir/")) { /* Do something with this entry. */ ... } } } else { /* Fail... */ }обратите внимание, что в Java 7, Вы можете создать
FileSystemиз файла JAR (zip), а затем используйте механизмы обхода и фильтрации каталогов NIO для поиска по нему. Это облегчило бы написание кода, который обрабатывает банки и" взорванные " каталоги.
код, который работает как для IDE и .файлы jar:
import java.io.*; import java.net.*; import java.nio.file.*; import java.util.*; import java.util.stream.*; public class ResourceWalker { public static void main(String[] args) throws URISyntaxException, IOException { URI uri = ResourceWalker.class.getResource("/resources").toURI(); Path myPath; if (uri.getScheme().equals("jar")) { FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap()); myPath = fileSystem.getPath("/resources"); } else { myPath = Paths.get(uri); } Stream<Path> walk = Files.walk(myPath, 1); for (Iterator<Path> it = walk.iterator(); it.hasNext();){ System.out.println(it.next()); } } }
Эриксона ответ прекрасно работал:
вот рабочий код.
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource(); List<String> list = new ArrayList<String>(); if( src != null ) { URL jar = src.getLocation(); ZipInputStream zip = new ZipInputStream( jar.openStream()); ZipEntry ze = null; while( ( ze = zip.getNextEntry() ) != null ) { String entryName = ze.getName(); if( entryName.startsWith("images") && entryName.endsWith(".png") ) { list.add( entryName ); } } } webimages = list.toArray( new String[ list.size() ] );и я просто изменить мой метод загрузки из этого:
File[] webimages = ... BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex].getName() ));для этого:
String [] webimages = ... BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex]));
Я хотел бы расширить на acheron55 в ответ, так как это очень небезопасное решение, по нескольким причинам:
- он не закрывает
Так что я думаю, моя главная проблема будет, как узнать имя jar, где живет мой основной класс.
предполагая, что ваш проект упакован в банку (не обязательно верно!), вы можете использовать загрузчик классов.getResource() или findResource () с именем класса (далее .класс), чтобы получить банку, которая содержит данный класс. Вам нужно будет разобрать имя jar из URL-адреса, который возвращается (не так сложно), который я оставлю в качестве упражнения для читателя :-)
обязательно проверьте для случая, когда класс не является частью jar.
вот метод, который я написал для "run all JUnits under a package". Вы должны быть в состоянии адаптировать его к вашим потребностям.
private static void findClassesInJar(List<String> classFiles, String path) throws IOException { final String[] parts = path.split("\Q.jar\\E"); if (parts.length == 2) { String jarFilename = parts[0] + ".jar"; String relativePath = parts[1].replace(File.separatorChar, '/'); JarFile jarFile = new JarFile(jarFilename); final Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { final JarEntry entry = entries.nextElement(); final String entryName = entry.getName(); if (entryName.startsWith(relativePath)) { classFiles.add(entryName.replace('/', File.separatorChar)); } } } }изменить: Ах, в этом случае, вы можете также захотеть этот фрагмент (тот же случай использования :) )
private static File findClassesDir(Class<?> clazz) { try { String path = clazz.getProtectionDomain().getCodeSource().getLocation().getFile(); final String codeSourcePath = URLDecoder.decode(path, "UTF-8"); final String thisClassPath = new File(codeSourcePath, clazz.getPackage().getName().repalce('.', File.separatorChar)); } catch (UnsupportedEncodingException e) { throw new AssertionError("impossible", e); } }
файл jar - это просто zip-файл со структурированным манифестом. Вы можете открыть файл jar с помощью обычных инструментов Java zip и сканировать содержимое файла таким образом, раздувать потоки и т. д. Затем используйте это в вызове getResourceAsStream, и это должно быть все hunky dory.
редактировать / после уточнения
InputStream inputStream = SomeClass.class.getClassLoader().getResourceAsStream("image.jpg"); JPEGImageReaderSpi imageReaderSpi = new JPEGImageReaderSpi(); ImageReader ir = imageReaderSpi.createReaderInstance(); ImageInputStream iis = new MemoryCacheImageInputStream(inputStream); ir.setInput(iis); .... ir.read(0); //will hand us a buffered image
учитывая фактический файл JAR, вы можете перечислить содержимое с помощью
JarFile.entries(). Однако вам нужно будет знать местоположение файла JAR - вы не можете просто попросить загрузчик классов перечислить все, что он может получить.вы должны быть в состоянии определить местоположение файла JAR на основе URL, возвращенного из
ThisClassName.class.getResource("ThisClassName.class"), но это может быть немного неудобный.
некоторое время назад я сделал функцию, которая получает classess изнутри JAR:
public static Class[] getClasses(String packageName) throws ClassNotFoundException{ ArrayList<Class> classes = new ArrayList<Class> (); packageName = packageName.replaceAll("\." , "/"); File f = new File(jarName); if(f.exists()){ try{ JarInputStream jarFile = new JarInputStream( new FileInputStream (jarName)); JarEntry jarEntry; while(true) { jarEntry=jarFile.getNextJarEntry (); if(jarEntry == null){ break; } if((jarEntry.getName ().startsWith (packageName)) && (jarEntry.getName ().endsWith (".class")) ) { classes.add(Class.forName(jarEntry.getName(). replaceAll("/", "\."). substring(0, jarEntry.getName().length() - 6))); } } } catch( Exception e){ e.printStackTrace (); } Class[] classesA = new Class[classes.size()]; classes.toArray(classesA); return classesA; }else return null; }
пример использования размышления библиотека для рекурсивного сканирования classpath по шаблону имени регулярного выражения, дополненному парой гуавы льготы для извлечения содержимого ресурсов:
Reflections reflections = new Reflections("com.example.package", new ResourcesScanner()); Set<String> paths = reflections.getResources(Pattern.compile(".*\.template$")); Map<String, String> templates = new LinkedHashMap<>(); for (String path : paths) { log.info("Found " + path); String templateName = Files.getNameWithoutExtension(path); URL resource = getClass().getClassLoader().getResource(path); String text = Resources.toString(resource, StandardCharsets.UTF_8); templates.put(templateName, text); }это работает как с jars, так и с разнесенными классами.
есть две очень полезные утилиты, которые называются JarScan:
см. Также этот вопрос: JarScan, сканировать все файлы JAR во всех подпапках для конкретного класса
я портировал ответ acheron55 на Java 7 и закрыл
просто другой способ перечисления / чтения файлов из URL-адреса jar, и он делает это рекурсивно для вложенных jars
https://gist.github.com/trung/2cd90faab7f75b3bcbaa
URL urlResource = Thead.currentThread().getContextClassLoader().getResource("foo"); JarReader.read(urlResource, new InputStreamCallback() { @Override public void onFile(String name, InputStream is) throws IOException { // got file name and content stream } });
Comments