subcarpetas seleccionar rutas recorrer manipulacion manejo gestor ejemplos directorios clase carpetas carpeta archivos java jar getresource

java - seleccionar - Copiar directorio desde un archivo jar



manipulacion de archivos en java (9)

Aquí hay una versión de trabajo del proyecto 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<JarEntry> 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(); } }

Recientemente he desarrollado una aplicación y he creado el archivo jar.

Una de mis clases crea un directorio de salida, llenándolo con archivos de su recurso.

Mi código es algo como esto:

// 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); }

Desafortunadamente esto no funciona.

Intenté lo siguiente sin suerte:

Mientras escribía esto, estaba pensando en lugar de tener un directorio de plantilla en la ruta de recursos con un archivo zip. Haciéndolo de esta manera podría obtener el archivo como inputStream y descomprimirlo donde lo necesite. Pero no estoy seguro si es la forma correcta.


Creo que su enfoque de usar un archivo zip tiene sentido. Presumiblemente, harás un getResourceAsStream para acceder a las getResourceAsStream internas del getResourceAsStream zip, que lógicamente se parecerá a un árbol de directorios.

Un enfoque esqueleto:

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 }


Gracias por la solución! Para otros, lo siguiente no hace uso de las clases auxiliares (excepto StringUtils)

/ Agregué información adicional para esta solución, verifique el final del código, 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<JarEntry> 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(); } }

Utiliza solo una biblioteca externa de Apache Software Foundation, sin embargo, las funciones utilizadas son solo:

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; }

Mi conocimiento está limitado a la licencia de Apache, pero puede usar estos métodos en su código sin biblioteca. Sin embargo, no soy responsable de los problemas de licencia, si los hay.


He enfrentado el problema de similair recientemente. Intenté extraer la carpeta de los recursos de Java. Así que resolví este problema con Spring PathMatchingResourcePatternResolver .

Este código obtiene todos los archivos y directorios del recurso especificado:

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

Y esta es la clase que copia todos los archivos y directorios del recurso a la ruta del disco.

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); } }

}


La respuesta de lpiepiora, es correcta! Pero hay un problema menor, la fuente, debe ser una URL de tarro. Cuando la ruta de origen es la ruta a un sistema de archivos, el código anterior no funcionará correctamente. Para resolver este problema, debe usar ReferencePath, el código, que puede obtener del siguiente enlace: Leer del sistema de archivos a través del objeto FileSystem El nuevo código de copyFromJar debería:

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<Path>() { 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")); }


No estoy seguro de qué es FileHelper o qué hace, pero NO podrá copiar archivos (o directorios) directamente desde JAR. Usar InputStream como has mencionado es la forma correcta (ya sea de jar o 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();

Tendrá que hacer lo anterior (manejando las excepciones de manera apropiada, por supuesto) para cada uno de sus archivos. Es posible o no (dependiendo de la configuración de su implementación) leer el archivo jar en cuestión como JarFile (por JarFile , puede que no esté disponible como un archivo real si se implementa como parte de una aplicación web no expandida). Si puede leerlo, debería poder recorrer la lista de instancias de JarEntry y reconstituir la estructura de su directorio; de lo contrario, es posible que deba almacenarlo en otro lugar (por ejemplo, dentro de un recurso de texto o xml)

Es posible que desee echar un vistazo a la biblioteca Commons IO , que proporciona una gran cantidad de funciones de flujo / archivo de uso común, incluida la copia.


Odiaba la idea de usar el método de archivo ZIP publicado anteriormente, por lo que se me ocurrió lo siguiente.

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)); } } } }

Ejemplo de uso (copia todos los archivos del recurso "classpath" a "$ {homeDirectory} / config":

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

Esto debería funcionar tanto para copiar desde archivos planos como archivos Jar.

Nota: el código anterior utiliza algunas clases de utilidades personalizadas (FileUtils, CollectionUtils), así como algunas de Apache commons-lang (StringUtils), pero las funciones deben tener un nombre bastante obvio.


Podría usar el ClassLoader para obtener una transmisión al recurso . Una vez que haya obtenido un InputStream, puede leer y escribir el contenido del flujo en un OutputStream.

En su caso, deberá crear varias instancias de OutputStream, una para cada archivo que desee copiar en el destino. Esto, por supuesto, requiere que conozca los nombres de los archivos de antemano.

Para esta tarea, se prefiere usar getResourceAsStream, en lugar de getResource o getResources ().


Usando Java7 + esto puede lograrse creando FileSystem y luego usando walkFileTree para copiar archivos recursivamente.

public void copyFromJar(String source, final Path target) throws URISyntaxException, IOException { URI resource = getClass().getResource("").toURI(); FileSystem fileSystem = FileSystems.newFileSystem( resource, Collections.<String, String>emptyMap() ); final Path jarPath = fileSystem.getPath(source); Files.walkFileTree(jarPath, new SimpleFileVisitor<Path>() { 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; } }); }

El método se puede utilizar de esta manera:

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