2010-02-16 28 views
28

Ho un file in un file JAR. È 1.txt, ad esempio.Come leggere un file da un file jar?

Come posso accedervi? Il mio codice sorgente è:

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; 
+0

vedere http://stackoverflow.com/questions/16842306 – yegor256

+0

possibile duplicato di [Come si legge un file di risorse da un file jar Java?] (Http://stackoverflow.com/questions/403256/how-do-i-read-a-res ource-file-da-un-java-jar-file) – davecom

+0

possibile duplicato di [Come leggere un file da jar in Java?] (http://stackoverflow.com/questions/3369794/how-to-a-read -file-from-jar-in-java) – Qix

risposta

27

Non è possibile utilizzare File, poiché questo file non esiste in modo indipendente sul file system. Invece è necessario getResourceAsStream(), in questo modo:

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

Supponendo che la classe chiamante si trovi all'interno del file jar, ovviamente.Altrimenti può semplicemente decomprimerlo e leggerlo usando le classi in 'java.util.jar' (o anche più semplice, come un semplice file zip vecchio usando' java.util.zip'). –

4

Qualcosa di simile a this answer è quello che serve.

È necessario estrarre il file dall'archivio in quel modo speciale.

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

BufferedReader non eccetto l'argomento 'InputStream' – Bozho

+0

@Bozho Grazie, leggera supervisione da parte mia. – jjnguy

+0

Sono stato troppo bloccato con questo grazie al tuo metodo di lavoro. –

46

Se il vaso è sul classpath:

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

Se non lo è nel classpath, quindi è possibile accedervi tramite:

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

Assicurati anche di includere quel punto esclamativo dopo il barattolo. Non è opzionale. – hsmishka

+0

C'è un modo per testarlo? (usando jUnit, testNG, Spock, ...). L'ho provato, ma i file non sono mai stati trovati durante i test. – Edward

+0

Grazie per la risposta. Questa parte "url.openStream();" era quello di cui avevo bisogno. – jmgoyesc

4

un file jar è un lampo file di .....

Quindi, per leggere un file jar, provare

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

Spero che questo aiuti.

+0

Le altre risposte sono corrette, ho appena dato un'altra alternativa. –

0

Ho incontrato questo stesso problema diverse volte prima. Speravo in JDK 7 che qualcuno avrebbe scritto un filesystem classpath, ma purtroppo non ancora.

Spring dispone della classe di risorse che consente di caricare le risorse del percorso di classe in modo abbastanza gradevole.

Le risposte sono state molto buone, ma ho pensato che avrei potuto aggiungere alla discussione mostrando un esempio che funziona con i file e le directory che sono risorse del percorso di classe.

Ho scritto un piccolo prototipo per risolvere questo problema. Il prototipo non gestisce ogni caso limite, ma gestisce la ricerca di risorse nelle directory contenute nei file jar.

Ho usato Stack Overflow per un bel po '. Questa è la prima volta che ricordo di aver risposto a una domanda, quindi perdonami se vado a lungo (è la mia natura).

 
    

    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. 
    * <pre> 
    *    <dependency> 
    *     <groupId>invoke</groupId> 
    *     <artifactId>invoke</artifactId> 
    *     <version>1.0-SNAPSHOT</version> 
    *    </dependency> 
    * 
    *    <dependency> 
    *     <groupId>node</groupId> 
    *     <artifactId>node</artifactId> 
    *     <version>1.0-SNAPSHOT</version> 
    *    </dependency> 
    * </pre> 
    * The jar files each have a file under /org/node/ called resource.txt. 
    * <br /> 
    * 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. 
    * <br /> 
    */ 
    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(); 
        } 

       } 

      } 
     } 

    } 


 

You can see a fuller example here with the sample output.

1

questo ha lavorato per me per copiare un file txt da file jar in un altro file 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<JarEntry> 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(); 
    } 
     } 
      } 
-1
InputStream inputStreamLastName = this.getClass().getClassLoader().getResourceAsStream("path of file"); 


    try { 

     br = new BufferedReader(new InputStreamReader(inputStreamLastName, "UTF-8")); 
     String sCurrentLine; 
     ArrayList<String> lastNamesList = new ArrayList<String>(); 
     while ((sCurrentLine = br.readLine()) != null) { 

      if(sCurrentLine.length()>=min && sCurrentLine.length()<=max){ 
       lastNamesList.add(sCurrentLine); 
      } 

     } 
+0

Aggiungi una spiegazione con la risposta per come questa risposta aiuta l'OP a risolvere il problema attuale –

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