2010-02-16 39 views
28

Tôi có tệp trong tệp JAR. Đó là 1.txt, chẳng hạn.Cách đọc tệp từ tệp jar?

Tôi làm cách nào để truy cập? Mã nguồn của tôi là:

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

thấy http://stackoverflow.com/questions/16842306 – yegor256

+0

có thể trùng lặp của [Làm cách nào để đọc tệp tài nguyên từ tệp jar Java?] (Http://stackoverflow.com/questions/403256/how-do-i-read-a-res ource-file-from-a-java-jar-file) – davecom

+0

có thể trùng lặp của [Cách đọc tệp từ jar trong Java?] (http://stackoverflow.com/questions/3369794/how-to-a-read -file-from-jar-in-java) – Qix

Trả lời

27

Bạn không thể sử dụng Tệp vì tệp này không tồn tại độc lập trên hệ thống tệp. Thay vào đó, bạn cần getResourceAsStream(), như vậy:

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

Giả sử lớp gọi nằm trong tệp jar của khóa học.Nếu không, anh ta có thể giải nén nó bằng cách đọc nó bằng cách sử dụng các lớp trong 'java.util.jar' (hoặc thậm chí cơ bản hơn, như một tệp zip cũ bằng cách sử dụng' java.util.zip'). –

4

Điều gì đó tương tự như this answer là những gì bạn cần.

Bạn cần phải kéo tệp ra khỏi lưu trữ theo cách đặc biệt đó.

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

BufferedReader không ngoại trừ đối số 'InputStream' – Bozho

+0

@Bozho Cảm ơn, giám sát nhẹ về phía tôi. – jjnguy

+0

tôi đã quá khó khăn với điều này nhờ công việc phương pháp của bạn. –

46

Nếu jar của bạn là trên classpath:

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

Nếu nó không phải là trên classpath, sau đó bạn có thể truy cập nó thông qua:

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

Cũng đảm bảo bao gồm dấu chấm than đó sau bình. Nó không phải là tùy chọn. – hsmishka

+0

Có cách nào để kiểm tra điều này không? (sử dụng jUnit, testNG, Spock, ...). Tôi đã thử nó, nhưng các tập tin không bao giờ được tìm thấy trong các bài kiểm tra. – Edward

+0

Cảm ơn câu trả lời của bạn. Phần này "url.openStream();" là những gì tôi cần. – jmgoyesc

4

Một file Jar là một zip file .....

Vì vậy, để đọc tệp jar, hãy thử

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

Hy vọng điều này sẽ hữu ích.

+0

Các câu trả lời khác là chính xác, tôi chỉ đưa ra một giải pháp thay thế khác. –

0

Tôi đã gặp phải vấn đề tương tự này vài lần trước đây. Tôi đã hy vọng trong JDK 7 rằng ai đó sẽ viết một hệ thống tập tin classpath, nhưng vẫn chưa.

Mùa xuân có lớp Tài nguyên cho phép bạn tải các tài nguyên lớp học khá độc đáo.

Câu trả lời đã rất tốt, nhưng tôi nghĩ tôi có thể thêm vào cuộc thảo luận bằng cách hiển thị ví dụ hoạt động với các tệp và thư mục là tài nguyên classpath.

Tôi đã viết một mẫu thử nghiệm nhỏ để giải quyết vấn đề này. Nguyên mẫu không xử lý mọi trường hợp cạnh, nhưng nó xử lý tìm kiếm các tài nguyên trong các thư mục nằm trong các tệp jar.

Tôi đã sử dụng Stack Overflow cho đôi khi. Đây là lần đầu tiên tôi nhớ trả lời một câu hỏi để tha thứ cho tôi nếu tôi đi lâu (đó là bản chất của tôi).

 
    

    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

này đã làm việc cho tôi để sao chép một tập tin txt từ file jar vào một tập tin 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

Thêm một số giải thích với câu trả lời cho cách câu trả lời này giúp OP trong việc khắc phục sự cố hiện tại –

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