Скопировать каталог из файла jar

Недавно я разработал приложение и создал файл jar.

Один из моих classов создает выходной каталог, заполняя его файлами из своего ресурса.

Мой код выглядит примерно так:

// Copy files from dir "template" in this class resource to output. private void createOutput(File output) throws IOException { File template = new File(FileHelper.URL2Path(getClass().getResource("template"))); FileHelper.copyDirectory(template, output); } 

К сожалению, это не работает.

Я попробовал следующее без везения:

  • Использование Streams для решения подобных задач на других classах, но это не работает с dirs. Код был похож на http://www.exampledepot.com/egs/java.io/CopyFile.html

  • Создание шаблона файла с new File(getClass().getResource("template").toUri())

При написании этого я думал, вместо того, чтобы иметь шаблон dir в пути ресурса, имеющий его zip-файл. Сделав это таким образом, я мог бы получить файл как inputStream и разархивировать его там, где мне нужно. Но я не уверен, что это правильный путь.

Я думаю, что ваш подход к использованию zip-файла имеет смысл. Предположительно, вы получите getResourceAsStream чтобы получить внутреннюю часть zip, которая будет логически выглядеть как дерево каталогов.

Скелетный подход:

 InputStream is = getClass().getResourceAsStream("my_embedded_file.zip"); ZipInputStream zis = new ZipInputStream(is); ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { // do something with the entry - for example, extract the data } 

Спасибо за решение! Для других следующее не использует вспомогательные classы (кроме StringUtils)

/ Я добавил дополнительную информацию для этого решения, проверьте конец кода, Zegor V /

 public class FileUtils { public static boolean copyFile(final File toCopy, final File destFile) { try { return FileUtils.copyStream(new FileInputStream(toCopy), new FileOutputStream(destFile)); } catch (final FileNotFoundException e) { e.printStackTrace(); } return false; } private static boolean copyFilesRecusively(final File toCopy, final File destDir) { assert destDir.isDirectory(); if (!toCopy.isDirectory()) { return FileUtils.copyFile(toCopy, new File(destDir, toCopy.getName())); } else { final File newDestDir = new File(destDir, toCopy.getName()); if (!newDestDir.exists() && !newDestDir.mkdir()) { return false; } for (final File child : toCopy.listFiles()) { if (!FileUtils.copyFilesRecusively(child, newDestDir)) { return false; } } } return true; } public static boolean copyJarResourcesRecursively(final File destDir, final JarURLConnection jarConnection) throws IOException { final JarFile jarFile = jarConnection.getJarFile(); for (final Enumeration e = jarFile.entries(); e.hasMoreElements();) { final JarEntry entry = e.nextElement(); if (entry.getName().startsWith(jarConnection.getEntryName())) { final String filename = StringUtils.removeStart(entry.getName(), // jarConnection.getEntryName()); final File f = new File(destDir, filename); if (!entry.isDirectory()) { final InputStream entryInputStream = jarFile.getInputStream(entry); if(!FileUtils.copyStream(entryInputStream, f)){ return false; } entryInputStream.close(); } else { if (!FileUtils.ensureDirectoryExists(f)) { throw new IOException("Could not create directory: " + f.getAbsolutePath()); } } } } return true; } public static boolean copyResourcesRecursively( // final URL originUrl, final File destination) { try { final URLConnection urlConnection = originUrl.openConnection(); if (urlConnection instanceof JarURLConnection) { return FileUtils.copyJarResourcesRecursively(destination, (JarURLConnection) urlConnection); } else { return FileUtils.copyFilesRecusively(new File(originUrl.getPath()), destination); } } catch (final IOException e) { e.printStackTrace(); } return false; } private static boolean copyStream(final InputStream is, final File f) { try { return FileUtils.copyStream(is, new FileOutputStream(f)); } catch (final FileNotFoundException e) { e.printStackTrace(); } return false; } private static boolean copyStream(final InputStream is, final OutputStream os) { try { final byte[] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) > 0) { os.write(buf, 0, len); } is.close(); os.close(); return true; } catch (final IOException e) { e.printStackTrace(); } return false; } private static boolean ensureDirectoryExists(final File f) { return f.exists() || f.mkdir(); } } 

Он использует только одну внешнюю библиотеку из Apache Software Foundation, однако используемые функции:

  public static String removeStart(String str, String remove) { if (isEmpty(str) || isEmpty(remove)) { return str; } if (str.startsWith(remove)){ return str.substring(remove.length()); } return str; } public static boolean isEmpty(CharSequence cs) { return cs == null || cs.length() == 0; } 

Мои знания ограничены лицензией Apache, но вы можете использовать эти методы в своем коде без библиотеки. Тем не менее, я не несу ответственности за проблемы с лицензиями, если они есть.

Используя Java7 +, это может быть достигнуто путем создания FileSystem а затем с помощью walkFileTree для рекурсивного копирования файлов.

 public void copyFromJar(String source, final Path target) throws URISyntaxException, IOException { URI resource = getClass().getResource("").toURI(); FileSystem fileSystem = FileSystems.newFileSystem( resource, Collections.emptyMap() ); final Path jarPath = fileSystem.getPath(source); Files.walkFileTree(jarPath, new SimpleFileVisitor() { private Path currentTarget; @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { currentTarget = target.resolve(jarPath.relativize(dir).toString()); Files.createDirectories(currentTarget); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.copy(file, target.resolve(jarPath.relativize(file).toString()), REPLACE_EXISTING); return FileVisitResult.CONTINUE; } }); } 

Метод можно использовать следующим образом:

 copyFromJar("/path/to/the/template/in/jar", Paths.get("/tmp/from-jar")) 

Я ненавидел идею использования метода ZIP-файла, опубликованного ранее, поэтому я придумал следующее.

 public void copyResourcesRecursively(URL originUrl, File destination) throws Exception { URLConnection urlConnection = originUrl.openConnection(); if (urlConnection instanceof JarURLConnection) { copyJarResourcesRecursively(destination, (JarURLConnection) urlConnection); } else if (urlConnection instanceof FileURLConnection) { FileUtils.copyFilesRecursively(new File(originUrl.getPath()), destination); } else { throw new Exception("URLConnection[" + urlConnection.getClass().getSimpleName() + "] is not a recognized/implemented connection type."); } } public void copyJarResourcesRecursively(File destination, JarURLConnection jarConnection ) throws IOException { JarFile jarFile = jarConnection.getJarFile(); for (JarEntry entry : CollectionUtils.iterable(jarFile.entries())) { if (entry.getName().startsWith(jarConnection.getEntryName())) { String fileName = StringUtils.removeStart(entry.getName(), jarConnection.getEntryName()); if (!entry.isDirectory()) { InputStream entryInputStream = null; try { entryInputStream = jarFile.getInputStream(entry); FileUtils.copyStream(entryInputStream, new File(destination, fileName)); } finally { FileUtils.safeClose(entryInputStream); } } else { FileUtils.ensureDirectoryExists(new File(destination, fileName)); } } } } 

Пример использования (копирует все файлы из ресурса конфигурации пути «config» в «$ {homeDirectory} / config»:

 File configHome = new File(homeDirectory, "config/"); //noinspection ResultOfMethodCallIgnored configHome.mkdirs(); copyResourcesRecursively(super.getClass().getResource("/config"), configHome); 

Это должно работать как для копирования как с плоских файлов, так и с файлов Jar.

Примечание. В приведенном выше коде используются некоторые пользовательские classы утилиты (FileUtils, CollectionUtils), а также некоторые из Apache commons-lang (StringUtils), но функции должны быть названы довольно явно.

Я не уверен, что FileHelper есть или делает, но вы НЕ сможете копировать файлы (или каталоги) непосредственно из JAR. Использование InputStream, как вы упомянули, является правильным способом (из jar или zip):

 InputStream is = getClass().getResourceAsStream("file_in_jar"); OutputStream os = new FileOutputStream("dest_file"); byte[] buffer = new byte[4096]; int length; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } os.close(); is.close(); 

Вам нужно будет сделать выше (обработка исключений, конечно, конечно) для каждого из ваших файлов. Вы можете или не сможете (в зависимости от конфигурации развертывания) читать JAR- файл под вопросом как JarFile (он может быть недоступен как фактический файл, если он развернут как часть нерасширенного веб-приложения, например). Если вы можете прочитать его, вы должны иметь возможность перебирать список экземпляров JarEntry и тем самым восстанавливать структуру своего каталога; в противном случае вам может потребоваться сохранить его в другом месте (например, в текстовом или XML-ресурсе)

Возможно, вам захочется взглянуть на библиотеку Commons IO – она ​​предоставляет множество широко используемых функций streamа / файла, включая копирование.

Вот рабочая версия проекта tess4j :

  /** * This method will copy resources from the jar file of the current thread and extract it to the destination folder. * * @param jarConnection * @param destDir * @throws IOException */ public void copyJarResourceToFolder(JarURLConnection jarConnection, File destDir) { try { JarFile jarFile = jarConnection.getJarFile(); /** * Iterate all entries in the jar file. */ for (Enumeration e = jarFile.entries(); e.hasMoreElements();) { JarEntry jarEntry = e.nextElement(); String jarEntryName = jarEntry.getName(); String jarConnectionEntryName = jarConnection.getEntryName(); /** * Extract files only if they match the path. */ if (jarEntryName.startsWith(jarConnectionEntryName)) { String filename = jarEntryName.startsWith(jarConnectionEntryName) ? jarEntryName.substring(jarConnectionEntryName.length()) : jarEntryName; File currentFile = new File(destDir, filename); if (jarEntry.isDirectory()) { currentFile.mkdirs(); } else { InputStream is = jarFile.getInputStream(jarEntry); OutputStream out = FileUtils.openOutputStream(currentFile); IOUtils.copy(is, out); is.close(); out.close(); } } } } catch (IOException e) { // TODO add logger e.printStackTrace(); } } 

Вы можете использовать ClassLoader для получения streamа к ресурсу . Получив InputStream, вы можете прочитать и записать содержимое streamа в OutputStream.

В вашем случае вам нужно создать несколько экземпляров OutputStream, по одному для каждого файла, который вы хотите скопировать в пункт назначения. Это, конечно, требует, чтобы вы знали имена файлов перед началом работы.

Для этой задачи предпочтительнее использовать getResourceAsStream, а не getResource или getResources ().

Ответ lpiepiora, правильный! Но есть незначительная проблема, источник, должен быть банком Url. Если исходный путь – путь к файловой системе, то приведенный выше код не будет работать должным образом. Чтобы решить эту проблему, вы должны использовать ReferencePath, код, который вы можете получить по следующей ссылке: читать из файловой системы через объект FileSystem . Новый код copyFromJar должен выглядеть так:

 public class ResourcesUtils { public static void copyFromJar(final String sourcePath, final Path target) throws URISyntaxException, IOException { final PathReference pathReference = PathReference.getPath(new URI(sourcePath)); final Path jarPath = pathReference.getPath(); Files.walkFileTree(jarPath, new SimpleFileVisitor() { private Path currentTarget; @Override public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { currentTarget = target.resolve(jarPath.relativize(dir) .toString()); Files.createDirectories(currentTarget); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { Files.copy(file, target.resolve(jarPath.relativize(file) .toString()), StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } }); } public static void main(final String[] args) throws MalformedURLException, URISyntaxException, IOException { final String sourcePath = "jar:file:/c:/temp/example.jar!/src/main/resources"; ResourcesUtils.copyFromJar(sourcePath, Paths.get("c:/temp/resources")); } 

Недавно я столкнулся с проблемой similair. Я попытался извлечь папку из java-ресурсов. Поэтому я решил эту проблему с помощью Spring PathMatchingResourcePatternResolver .

Этот код получает все файлы и каталоги из указанного ресурса:

  ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourceFolder + "/**"); 

И это class, который копирует все файлы и каталоги с ресурса на путь к диску.

 public class ResourceExtractor { public static final Logger logger = Logger.getLogger(ResourceExtractor.class); public void extract(String resourceFolder, String destinationFolder){ try { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourceFolder + "/**"); URI inJarUri = new DefaultResourceLoader().getResource("classpath:" + resourceFolder).getURI(); for (Resource resource : resources){ String relativePath = resource .getURI() .getRawSchemeSpecificPart() .replace(inJarUri.getRawSchemeSpecificPart(), ""); if (relativePath.isEmpty()){ continue; } if (relativePath.endsWith("/") || relativePath.endsWith("\\")) { File dirFile = new File(destinationFolder + relativePath); if (!dirFile.exists()) { dirFile.mkdir(); } } else{ copyResourceToFilePath(resource, destinationFolder + relativePath); } } } catch (IOException e){ logger.debug("Extraction failed!", e ); } } private void copyResourceToFilePath(Resource resource, String filePath) throws IOException{ InputStream resourceInputStream = resource.getInputStream(); File file = new File(filePath); if (!file.exists()) { FileUtils.copyInputStreamToFile(resourceInputStream, file); } } 

}

  • Инъекция зависимостей и JavaFX
  • Как преобразовать CamelCase в удобочитаемые имена на Java?
  • Преобразование даты и времени в другой часовой пояс в java
  • Что случилось с использованием ассоциативности компиляторами?
  • Регулярное выражение для соответствия подстроке, за которой не следует определенная другая подстрока
  • Ошибка java Lang UnsupportedClassVersion в Xamarin Studio
  • Лучше ли использовать String.format над строкой Concatenation в Java?
  • Spring MVC + JSON = 406 Не допускается
  • Альтернатива устаревшему getCellType
  • Как переключить JPanels внутри JFrame
  • Как реализовать автоматическое использование с помощью нового API AnalyzerInfixSuggester от Lucene?
  • Interesting Posts

    Применить функцию условно

    Как вызвать службу WCF с помощью ksoap2 на Android?

    Алгоритм графа для поиска всех соединений между двумя произвольными вершинами

    получение атрибутов схемы из модели Mongoose

    Как преобразовать неглубокий клон Git в полный клон?

    Как создать экземпляр типа, представленного параметром type в Scala

    Макет деятельности: class fragmentа: vs android: атрибуты name

    Форматирование Word – необходимо выравнивать слева направо, справа налево в одной строке

    Как настроить плитки (изменить / увеличить значок, изменить цвет) для настольных приложений на экране запуска?

    Эмулировать ключ Windows на сенсорной клавиатуре Windows 10

    Доступ к родительским данным во вложенном ретрансляторе, в HeaderTemplate

    Ошибка «Диспетчер Struts не может быть найден» при развертывании приложения на WebLogic 12.1.3

    Ошибка: «Не удалось найти Installable ISAM»

    Как создать новый шаблон проекта Eclipse?

    Зачем использовать синглтон вместо статических методов?

    Давайте будем гением компьютера.