如何从jar文件中读取文件?

32

我有一个在JAR文件中的文件,例如是 1.txt

我该如何访问它?我的源代码如下:

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;

请查看以下链接:https://dev59.com/23LYa4cB1Zd3GeqPbL2m - yegor256
可能是重复的问题:如何从Java jar文件中读取资源文件? - davecom
可能是重复的问题:如何在Java中从jar文件中读取文件? - Qix - MONICA WAS MISTREATED
7个回答

51

如果您的jar文件在类路径上:

InputStream is = YourClass.class.getResourceAsStream("1.txt");
如果它不在类路径上,则可以通过以下方式访问它:
URL url = new URL("jar:file:/absolute/location/of/yourJar.jar!/1.txt");
InputStream is = url.openStream();

2
请确保在jar后面加上感叹号。这不是可选的。 - hsmishka
有没有办法进行测试?(使用jUnit,testNG,Spock等)。我尝试过了,但是在测试期间找不到文件。 - Edward
谢谢你的回答。这部分代码 "url.openStream();" 是我需要的。 - jmgoyesc

29

由于该文件不是独立于文件系统存在的,因此您无法使用File。相反,您需要使用getResourceAsStream(),如下所示:

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

2
假设调用类当然在jar文件内。否则,他可以使用java.util.jar中的类(甚至更基本的是使用普通的zip文件,使用java.util.zip)来解压缩并读取它。 - Martin Wickman

8

Jar文件是一种压缩文件......

因此,要读取一个Jar文件,请尝试使用以下方法:

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

希望这能帮到您。

其他答案是正确的,我只是提供了另一种选择。 - Buhake Sindi

4

你需要的是类似于这个答案的方法。

你需要以特殊的方式从压缩文件中提取文件。

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

BufferedReader不接受InputStream参数。 - Bozho
@Bozho 谢谢,这是我疏忽了。 - jjnguy

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

2

我曾用以下方法成功将一个txt文件从jar文件中复制到另一个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
我之前遇到过这个问题好几次。 我希望在JDK 7中有人能编写一个classpath文件系统,但可惜并没有。 Spring有Resource类,可以很好地加载classpath资源。 答案非常好,但我认为我可以通过展示一个适用于作为classpath资源的文件和目录的示例来增加讨论。 我写了一个小型原型来解决这个问题。该原型不能处理每个边缘情况,但它确实可以处理在jar文件中的目录中查找资源的情况。 我已经使用Stack Overflow相当长时间了。如果我回答得太长,请原谅(这是我的天性)。
/** * 原型资源读取器。 * 此原型不包含错误检查。 * * * 我有两个设置好的原型jar文件。 *
 *             <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>
 * 
* 这些jar文件下各有一个名为resource.txt的文件,位于/org/node/目录下。 *
* 这只是一个类似于classpath://处理程序的原型。 * 我还在本项目的本地资源中添加了一个resource.foo.txt文件。 *
*/ public class ClasspathReader {
public static void main(String[] args) throws Exception {
/* 此项目包括两个jar文件,每个文件都有一个位于/org/node/目录下的资源,名为resource.txt。*/
/* 命名空间只是我用来查看目录中文件是否以命名空间开头的设备。 将命名空间视为文件扩展名,但它是文件的开始而不是结尾。 */ String namespace = "resource";
//someResource是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 = " + someResourceURI);
someResource = someResourceURI.getPath();
System.out.println("资源的路径 =" + someResource);
boolean isDir = !someResource.endsWith(".txt");
/** Classpath资源实际上永远不会以斜杠开头。 * 逻辑上它们确实是,但实际上你必须剥离它。 * 这是classpath资源的已知行为。 * 它使用斜杠工作,除非资源在jar文件中。 * 底线是,通过剥离它,它总是有效的。 */ if (someResource.startsWith("/")) { someResource = someResource.substring(1); }
/* 使用ClassLoader查找所有具有此名称的资源。 查找与我们正在查找的位置匹配的所有资源。*/ Enumeration resources = null;
/* 首先检查上下文类加载器。如果可以使用,请始终使用它。*/ try { resources = Thread.currentThread().getContextClassLoader().getResources(someResource); } catch (Exception ex) { ex.printStackTrace(); }
if (resources == null || !resources.hasMoreElements()) { resources = ClasspathReader.class.getClassLoader().getResources(someResource); }
//现在遍历来自类路径的资源的URL while (resources.hasMoreElements()) { URL resource = resources.nextElement();
/* 如果资源是文件,则只是意味着我们可以使用正常机制来扫描目录。*/ if (resource.getProtocol().equals("file")) { //如果它是一个文件,那么我们可以用正常的方式处理它。 handleFile(resource, namespace); continue; }
System.out.println("资源 " + resource);
/* 将这个字符串拆分成这样: jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/ 分成 这个 /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar 和这个 /org/node/ */ String[] split = resource.toString().split(":"); String[] split2 = split[2].split("!"); String zip

您可以在此处查看一个完整的示例及其输出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接