¿Cómo leer un archivo de un archivo jar?

Tengo un archivo en un archivo JAR. Es 1.txt , por ejemplo.

¿Cómo puedo acceder? Mi código fuente es:

 Double result=0.0; File file = new File("1.txt")); //how get this file from a jar file BufferedReader input = new BufferedReader(new FileReader(file)); String line; while ((line = input.readLine()) != null) { if(me==Integer.parseInt(line.split(":")[0])){ result= parseDouble(line.split(":")[1]); } } input.close(); return result; 

No puede usar File, ya que este archivo no existe de forma independiente en el sistema de archivos. En cambio, necesitas getResourceAsStream (), así:

 ... InputStream in = getClass().getResourceAsStream("/1.txt"); BufferedReader input = new BufferedReader(new InputStreamReader(in)); ... 

Si su jar está en el classpath:

 InputStream is = YourClass.class.getResourceAsStream("1.txt"); 

Si no está en el classpath, puede acceder a él a través de:

 URL url = new URL("jar:file:/absolute/location/of/yourJar.jar!/1.txt"); InputStream is = url.openStream(); 

Algo similar a esta respuesta es lo que necesitas.

Necesita extraer el archivo del archivo de esa manera especial.

 BufferedReader input = new BufferedReader(new InputStreamReader( this.getClass().getClassLoader().getResourceAsStream("1.txt"))); 

Un archivo Jar es un archivo zip …..

Entonces, para leer un archivo jar, intente

 ZipFile file = new ZipFile("whatever.jar"); if (file != null) { ZipEntries entries = file.entries(); //get entries from the zip file... if (entries != null) { while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); //use the entry to see if it's the file '1.txt' //Read from the byte using file.getInputStream(entry) } } } 

Espero que esto ayude.

 private String loadResourceFileIntoString(String path) { //path = "/resources/html/custom.css" for example BufferedReader buffer = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(path))); return buffer.lines().collect(Collectors.joining(System.getProperty("line.separator"))); } 

Me he encontrado con este mismo problema varias veces antes. Esperaba en JDK 7 que alguien escribiera un sistema de archivos classpath, pero todavía no.

Spring tiene la clase Resource que te permite cargar recursos classpath bastante bien.

Las respuestas han sido muy buenas, pero pensé que podría agregar algo más a la discusión mostrando un ejemplo que funciona con archivos y directorios que son recursos de classpath.

Escribí un pequeño prototipo para resolver este problema. El prototipo no maneja todos los casos extremos, pero maneja la búsqueda de recursos en los directorios que están en los archivos jar.

He usado Stack Overflow por bastante tiempo. Esta es la primera vez que recuerdo haber respondido una pregunta, así que perdóneme si voy a la larga (es mi naturaleza).

   package com.foo; import java.io.File; import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; import java.net.URI; import java.net.URL; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Prototype resource reader. * This prototype is devoid of error checking. * * * I have two prototype jar files that I have setup. * 
 *  * invoke * invoke * 1.0-SNAPSHOT *  * *  * node * node * 1.0-SNAPSHOT *  * 

* The jar files each have a file under /org/node/ called resource.txt. *
* This is just a prototype of what a handler would look like with classpath:// * I also have a resource.foo.txt in my local resources for this project. *
*/ public class ClasspathReader { public static void main(String[] args) throws Exception { /* This project includes two jar files that each have a resource located in /org/node/ called resource.txt. */ /* Name space is just a device I am using to see if a file in a dir starts with a name space. Think of namespace like a file extension but it is the start of the file not the end. */ String namespace = "resource"; //someResource is classpath. String someResource = args.length > 0 ? args[0] : //"classpath:///org/node/resource.txt"; It works with files "classpath:///org/node/"; //It also works with directories URI someResourceURI = URI.create(someResource); System.out.println("URI of resource = " + someResourceURI); someResource = someResourceURI.getPath(); System.out.println("PATH of resource =" + someResource); boolean isDir = !someResource.endsWith(".txt"); /** Classpath resource can never really start with a starting slash. * Logically they do, but in reality you have to strip it. * This is a known behavior of classpath resources. * It works with a slash unless the resource is in a jar file. * Bottom line, by stripping it, it always works. */ if (someResource.startsWith("/")) { someResource = someResource.substring(1); } /* Use the ClassLoader to lookup all resources that have this name. Look for all resources that match the location we are looking for. */ Enumeration resources = null; /* Check the context classloader first. Always use this if available. */ try { resources = Thread.currentThread().getContextClassLoader().getResources(someResource); } catch (Exception ex) { ex.printStackTrace(); } if (resources == null || !resources.hasMoreElements()) { resources = ClasspathReader.class.getClassLoader().getResources(someResource); } //Now iterate over the URLs of the resources from the classpath while (resources.hasMoreElements()) { URL resource = resources.nextElement(); /* if the resource is a file, it just means that we can use normal mechanism to scan the directory. */ if (resource.getProtocol().equals("file")) { //if it is a file then we can handle it the normal way. handleFile(resource, namespace); continue; } System.out.println("Resource " + resource); /* Split up the string that looks like this: jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/ into this /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar and this /org/node/ */ String[] split = resource.toString().split(":"); String[] split2 = split[2].split("!"); String zipFileName = split2[0]; String sresource = split2[1]; System.out.printf("After split zip file name = %s," + " \nresource in zip %s \n", zipFileName, sresource); /* Open up the zip file. */ ZipFile zipFile = new ZipFile(zipFileName); /* Iterate through the entries. */ Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); /* If it is a directory, then skip it. */ if (entry.isDirectory()) { continue; } String entryName = entry.getName(); System.out.printf("zip entry name %s \n", entryName); /* If it does not start with our someResource String then it is not our resource so continue. */ if (!entryName.startsWith(someResource)) { continue; } /* the fileName part from the entry name. * where /foo/bar/foo/bee/bar.txt, bar.txt is the file */ String fileName = entryName.substring(entryName.lastIndexOf("/") + 1); System.out.printf("fileName %s \n", fileName); /* See if the file starts with our namespace and ends with our extension. */ if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) { /* If you found the file, print out the contents fo the file to System.out.*/ try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) { StringBuilder builder = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { builder.append((char) ch); } System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n", entryName, builder); } catch (Exception ex) { ex.printStackTrace(); } } //use the entry to see if it's the file '1.txt' //Read from the byte using file.getInputStream(entry) } } } /** * The file was on the file system not a zip file, * this is here for completeness for this example. * otherwise. * * @param resource * @param namespace * @throws Exception */ private static void handleFile(URL resource, String namespace) throws Exception { System.out.println("Handle this resource as a file " + resource); URI uri = resource.toURI(); File file = new File(uri.getPath()); if (file.isDirectory()) { for (File childFile : file.listFiles()) { if (childFile.isDirectory()) { continue; } String fileName = childFile.getName(); if (fileName.startsWith(namespace) && fileName.endsWith("txt")) { try (FileReader reader = new FileReader(childFile)) { StringBuilder builder = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { builder.append((char) ch); } System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", childFile, builder); } catch (Exception ex) { ex.printStackTrace(); } } } } else { String fileName = file.getName(); if (fileName.startsWith(namespace) && fileName.endsWith("txt")) { try (FileReader reader = new FileReader(file)) { StringBuilder builder = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { builder.append((char) ch); } System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", fileName, builder); } catch (Exception ex) { ex.printStackTrace(); } } } } }

package com.foo; import java.io.File; import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; import java.net.URI; import java.net.URL; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Prototype resource reader. * This prototype is devoid of error checking. * * * I have two prototype jar files that I have setup. *

 *  * invoke * invoke * 1.0-SNAPSHOT *  * *  * node * node * 1.0-SNAPSHOT *  * 

* The jar files each have a file under /org/node/ called resource.txt. *
* This is just a prototype of what a handler would look like with classpath:// * I also have a resource.foo.txt in my local resources for this project. *
*/ public class ClasspathReader { public static void main(String[] args) throws Exception { /* This project includes two jar files that each have a resource located in /org/node/ called resource.txt. */ /* Name space is just a device I am using to see if a file in a dir starts with a name space. Think of namespace like a file extension but it is the start of the file not the end. */ String namespace = "resource"; //someResource is classpath. String someResource = args.length > 0 ? args[0] : //"classpath:///org/node/resource.txt"; It works with files "classpath:///org/node/"; //It also works with directories URI someResourceURI = URI.create(someResource); System.out.println("URI of resource = " + someResourceURI); someResource = someResourceURI.getPath(); System.out.println("PATH of resource =" + someResource); boolean isDir = !someResource.endsWith(".txt"); /** Classpath resource can never really start with a starting slash. * Logically they do, but in reality you have to strip it. * This is a known behavior of classpath resources. * It works with a slash unless the resource is in a jar file. * Bottom line, by stripping it, it always works. */ if (someResource.startsWith("/")) { someResource = someResource.substring(1); } /* Use the ClassLoader to lookup all resources that have this name. Look for all resources that match the location we are looking for. */ Enumeration resources = null; /* Check the context classloader first. Always use this if available. */ try { resources = Thread.currentThread().getContextClassLoader().getResources(someResource); } catch (Exception ex) { ex.printStackTrace(); } if (resources == null || !resources.hasMoreElements()) { resources = ClasspathReader.class.getClassLoader().getResources(someResource); } //Now iterate over the URLs of the resources from the classpath while (resources.hasMoreElements()) { URL resource = resources.nextElement(); /* if the resource is a file, it just means that we can use normal mechanism to scan the directory. */ if (resource.getProtocol().equals("file")) { //if it is a file then we can handle it the normal way. handleFile(resource, namespace); continue; } System.out.println("Resource " + resource); /* Split up the string that looks like this: jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/ into this /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar and this /org/node/ */ String[] split = resource.toString().split(":"); String[] split2 = split[2].split("!"); String zipFileName = split2[0]; String sresource = split2[1]; System.out.printf("After split zip file name = %s," + " \nresource in zip %s \n", zipFileName, sresource); /* Open up the zip file. */ ZipFile zipFile = new ZipFile(zipFileName); /* Iterate through the entries. */ Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); /* If it is a directory, then skip it. */ if (entry.isDirectory()) { continue; } String entryName = entry.getName(); System.out.printf("zip entry name %s \n", entryName); /* If it does not start with our someResource String then it is not our resource so continue. */ if (!entryName.startsWith(someResource)) { continue; } /* the fileName part from the entry name. * where /foo/bar/foo/bee/bar.txt, bar.txt is the file */ String fileName = entryName.substring(entryName.lastIndexOf("/") + 1); System.out.printf("fileName %s \n", fileName); /* See if the file starts with our namespace and ends with our extension. */ if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) { /* If you found the file, print out the contents fo the file to System.out.*/ try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) { StringBuilder builder = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { builder.append((char) ch); } System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n", entryName, builder); } catch (Exception ex) { ex.printStackTrace(); } } //use the entry to see if it's the file '1.txt' //Read from the byte using file.getInputStream(entry) } } } /** * The file was on the file system not a zip file, * this is here for completeness for this example. * otherwise. * * @param resource * @param namespace * @throws Exception */ private static void handleFile(URL resource, String namespace) throws Exception { System.out.println("Handle this resource as a file " + resource); URI uri = resource.toURI(); File file = new File(uri.getPath()); if (file.isDirectory()) { for (File childFile : file.listFiles()) { if (childFile.isDirectory()) { continue; } String fileName = childFile.getName(); if (fileName.startsWith(namespace) && fileName.endsWith("txt")) { try (FileReader reader = new FileReader(childFile)) { StringBuilder builder = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { builder.append((char) ch); } System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", childFile, builder); } catch (Exception ex) { ex.printStackTrace(); } } } } else { String fileName = file.getName(); if (fileName.startsWith(namespace) && fileName.endsWith("txt")) { try (FileReader reader = new FileReader(file)) { StringBuilder builder = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { builder.append((char) ch); } System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", fileName, builder); } catch (Exception ex) { ex.printStackTrace(); } } } } }

Puede ver un ejemplo más completo aquí con la salida de muestra.

Esto funcionó para que copie un archivo txt del archivo jar a otro archivo txt

 public static void copyTextMethod() throws Exception{ String inputPath = "path/to/.jar"; String outputPath = "Desktop/CopyText.txt"; File resStreamOut = new File(outputPath); int readBytes; JarFile file = new JarFile(inputPath); FileWriter fw = new FileWriter(resStreamOut); try{ Enumeration entries = file.entries(); while (entries.hasMoreElements()){ JarEntry entry = entries.nextElement(); if (entry.getName().equals("readMe/tempReadme.txt")) { System.out.println(entry +" : Entry"); InputStream is = file.getInputStream(entry); BufferedWriter output = new BufferedWriter(fw); while ((readBytes = is.read()) != -1) { output.write((char) readBytes); } System.out.println(outputPath); output.close(); } } } catch(Exception er){ er.printStackTrace(); } } } 
 InputStream inputStreamLastName = this.getClass().getClassLoader().getResourceAsStream("path of file"); try { br = new BufferedReader(new InputStreamReader(inputStreamLastName, "UTF-8")); String sCurrentLine; ArrayList lastNamesList = new ArrayList(); while ((sCurrentLine = br.readLine()) != null) { if(sCurrentLine.length()>=min && sCurrentLine.length()<=max){ lastNamesList.add(sCurrentLine); } }