jar获取资源文件的问题

目录

在开发环境中运行,如eclips

在src目录下

在非src目录下

以jar包形式运行,linux系统

在src目录下

在非src目录下,但在jar包内

在jar包外

jar包访问第三方依赖,的类路径配置






在开发环境中运行,如eclips

在src目录下

可以用绝对路径和相对路径来读取,绝对路径为文件在磁盘的存放位置,这里暂且不讨论。

用相对路径可按如下操作获取文件资源:

File file = new File("src/main/resources/properties/basecom.properties");
InputStream in = new FileInputStream(file);

也可以通过类加载方式:

//读取根目录下的tmp(src/):
// 第一种方法
InputStream in = App.class.getResourceAsStream("/tmp");
// 第二种方法
InputStream in =ClassLoader.getSystemClassLoader().getResourceAsStream("tmp");
//读取App类同级目录下的tmp(src/space/yukai)
// 第一种方法
InputStream in = App.class.getResourceAsStream("tmp");
// 第二种方法
InputStream in =ClassLoader.getSystemClassLoader().getResourceAsStream("space/yukai/tmp");
//第三种方法
InputStream in = App.class.getResourceAsStream("/space/yukai/tmp");
//读取MyClassloader同级目录下的tmp(src/space/yukai/classloader):
// 第一种方法
InputStream in = App.class.getResourceAsStream("classloader/tmp");
// 第二种方法
InputStream in =ClassLoader.getSystemClassLoader().getResourceAsStream("space/yukai/classloader/tmp");
//第三种方法
InputStream in = App.class.getResourceAsStream("/space/yukai/classloader/tmp");

在非src目录下

lib与src同级,想获取lib目录下的文件

File file = new File("./lib");
System.out.println(file.getAbsolutePath());
File[] listFiles = file.listFiles();

以jar包形式运行,linux系统

在src目录下

当将工程导出jar包或war包时可用以下方法获取

使用Class.getResource或者是ClassLoader.getResourceAsStream()将文件内容放到InputStream中

String s1 = this.getClass().getResource("/log4j.properties").getPath();

或者为:

String s1 = CodeTest.class.getResource("/log4j.properties").getPath();

注意,使用class的getRescource时,要注意路径前要加"/",即根目录,此处的根目录是src

若像如下使用:

String class_str = this.getClass().getResource("logback.xml").getPath();

则会出错如下:

使用ClassLoader时,如下:

this.getClass().getClassLoader().getResource()
在使用ClassLoader时,路径前面不能加"/",使用相对路径。

public void readProperties(){
		String ss = TempTest.class.getResource("/").getPath();
		System.out.println(ss);
		String s = new File(ss).getParentFile().getPath();
		System.out.println(s);
		String system_str = System.getProperty("user.dir");
		System.out.println(system_str);
}

运行结果如下:

 

将上述readProperties函数打包为jar包在命令行使用java -jar TempTest.jar运行时,结果如下:

 

由此可见,打包成jar包时和在ide中直接运行的结果并不一样,所以在jar包中的class类要访问自己jar包中的资源文件时,应该使用Class.getResource或者是getResourceAsStream放在InputStream中,再进行访问。但是该方法只能访问到src下的资源文件,因为其根目录对应的就是src,无法访问到项目根目录下src外的文件,如上述项目结构图中的blackWhite中的文件无法访问到,

关于class.getResource && classloader.getResource 的区别。

 

源码中:Class.getResourceAsStream(String name)

public InputStream getResourceAsStream(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResourceAsStream(name);
    }
    return cl.getResourceAsStream(name);
}

上面的代码可以看出, Class.getResourceAsStream(String name) 最终还是调用了 classloader.getResourceAsStream(String name) 。但是两者还是有一些区别的,注意 name =resolveName(name)这一行,Class.getResourceAsStream(String name)在这里做了一些处理:Class.resolveName(String name)

通过测试类进行测试:

public class App {
    public static void main(String[] args) {
    System.out.println("App.class.getClassLoader().getResource(\"\") : " +             
        App.class.getClassLoader().getResource(""));
    System.out.println("App.class.getClassLoader().getResource(\"/\") : " + 
        App.class.getClassLoader().getResource("/"));
    System.out.println("App.class.getResource(\"\") : " + App.class.getResource(""));
    System.out.println("App.class.getResource(\"/\") : " + App.class.getResource("/"));
    }
}

结果如下:

App.class.getClassLoader().getResource("") : 
              file:/D:/workspace/eclipse/cluster/TestClassloader/bin/
App.class.getClassLoader().getResource("/") : null
App.class.getResource("") : 
               file:/D:/workspace/eclipse/cluster/TestClassloader/bin/space/yukai/
App.class.getResource("/") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/

calssloder.getResource("")方法返回了classpath根路径(eclipse工程中,编译生成的类文件存放在/bin目录下);

calssloder.getResource("/")方法返回null,说明calssloder.getResource不支持以"/"开头的参数;

class.getResource("")方法返回了App.class所在的路径;

class.getResource("/")与calssloder.getResource("")表现一致,返回了classpath的根路径

 

在非src目录下,但在jar包内

如图想打jar包后能继续访问lib中的json文件,可以用JarFile类来实现。

package com.test.jar;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ReadSource {
	public static void main(String[] args) throws Exception {
		String path = ReadSource.class.getProtectionDomain().getCodeSource().getLocation().getPath();//获取jar包的绝对路径
		path = java.net.URLDecoder.decode(path, "UTF-8");//转换处理中文及空格,但是如果路径中包含中文,就会变成带“%xx%xx”格式的字符串。所以应该这样写才对:
		System.out.println("path: "+path);
		JarFile localJarFile = new JarFile(new File(path));
		 Enumeration<JarEntry> entries = localJarFile.entries();
		 while (entries.hasMoreElements()) {
             JarEntry jarEntry = entries.nextElement();
             System.out.println(jarEntry.getName());
             String innerPath = jarEntry.getName();
             if(innerPath.contains(".json")&& !innerPath.contains("jar")){
                 InputStream inputStream = 
                        ReadSource.class.getClassLoader().getResourceAsStream(innerPath);
                 BufferedReader br = new BufferedReader(new 
                        InputStreamReader(inputStream));         
                 String line="";
                 while((line=br.readLine())!=null){
                       System.out.println(innerPath+"内容为:"+line);
                 }
             }
         }
	}
}

结果:

在jar包外

比如在jar包同级目录下有名为testInfo的文件夹,

File file = new File("./testInfo");可获取该文件夹对象。

file.getAbsolutePath();可获取该文件夹对象的绝对路径。

jar包访问第三方依赖,的类路径配置

 

手动配置MANITAST.MF中的class_path配置,即需要的第三方jar包

打包可执行jar包时,MANIFEST.MF总是个让人头疼的东西,经常出现这种那种问题。

 

一个例子:

Manifest-Version: 1.0
Main-Class: test.Main
Class-Path: ./ ./lib/commons-collections-3.2.jar ./lib/commons-dbcp-1.2.2.jar ./lib/commons-lang-2.3.jar ./lib/commons-logging-1.1.jar

各部分解释:

Manifest-Version MF文件版本号

Main-Class 包含main方法的类

Class-Path 执行这个jar包时的ClassPath

 

以下是需要注意的各个要点:

  1. Manifest-Version、Main-Class和Class-Path后面跟着一个英文的冒号,冒号后面必须跟着一个空格,然后才是版本号、类和ClassPath。
  2. Class-Path中的各项应使用空格分隔,不是逗号或分号。 
  3. Class-Path中如果有很多项,写成一行打包的时候会报错line too long,这时需要把Class-Path分多行写。注意:从第二行开始,必须以两个空格开头,三个以上我没试过,不过不用空格开头和一个空格开头都是不行的,我已经试过了。
  4. Class-Path写完之后最后一定要有一个空行

5. jar包内有些配置文件想放在jar包外面,比如文件config.properties:如果这个文件是以路径方式载入的,比如new file("./config/config.properties"),那么将config.properties放在jar包相同目录下的config目录下即可,也就是说“./”路径等价于jar包所在目录;如果这个文件是以ClassPath下的文件这种方式载入的,比如在Spring中载入classpath:config.properties,则在MF文件的配置文件的ClassPath中添加“./”,然后将这个配置文件与jar包放在同一个目录即可,当然也可以在MF文件的配置文件的ClassPath中添加“./config/”,然后把配置文件都放在jar包相同目录下的config目录下。

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值