java获取jar包中的文件资源

问题描述:
  我们常常在代码中读取一些资源文件(比如图片,音乐,文本等等)。在单独运行的时候这些简单的处理不会有问题。但是当我们把代码打成一个jar包以后,即使将资源文件一并打包,这些东西也找不出来了。此时应该怎么办???

  我们在开发时,读取项目内的资源文件时,可以直接获取该资源文件在文件系统中的绝对路径。但是,一旦导出为jar包,就无法获取到资源文件的绝对路径。打完jar包以后资源(例如xml)等将被放在jar包下的第一层,这时使用上述路径就会错误,无法访问到资源。

一、问题示例

1.1 项目开发时

1
TestPath 文件内容:

package pro;
public class TestPath {
	public TestPath() {}
	public static String getFilePath(String fileName){
		return TestPath.class.getResource(fileName).getPath();
	}
}

主访问工程的main函数调用:

public static void main(String[] args) {
		String path = TestPath.getFilePath("data1.txt");
		System.out.println("path:"+path);
		File file = new File(path);
		if(file.exists() && file.isFile()){
			try {
				InputStream inputStream = new FileInputStream(file);
		        System.out.println(inputStream);
			} catch (Exception e) {
				System.err.println("解析文件"+file.getName()+"异常:");
				e.printStackTrace();
			}
		}
    }

输出结果:

path:/D:/eclipse_powflow/workspace/TestPathPro/bin/pro/data1.txt
java.io.FileInputStream@6bc7c054

1.2 打包成jar后

打包成jar包,并在主工程中引用,如下:
2
再执行main函数,输出结果如下:

path:file:/D:/eclipse_powflow/workspace/Test/lib/TestPathPro.jar!/pro/data1.txt

  我们能够看到,此时的路径并不是文件资源定位符的格式 (jar中资源有其专门的URL形式: jar:!/{entry} )。所以,如果jar包中的类源代码用File f=new File(相对路径);的形式,是不可能定位到文件资源的。这也是为什么源代码打包成jar文件后,调用jar包时会报出FileNotFoundException的症结所在了。
  我们不能用常规操作文件的方法来读取ResourceJar.jar中的资源文件res.txt,但可以通过Class类的getResourceAsStream()方法来获取 ,这种方法是如何读取jar中的资源文件的,这一点对于我们来说是透明的。如下节所示。

二、解决方案

2.1 解决方法

  把资源打入jar包,无论资源文件在系统的什么路径下,jar包中的字节码程序都可以找到该包中的资源。我们可以用类装载器(ClassLoader)来做到这一点:

1、ClassLoader :
  是类加载器的抽象类。它可以在运行时动态的获取加载类的运行信息。 可以这样说,当我们调用.jar中的Resource类时,JVM加载进Resource类,并记录下Resource运行时信息(包括Resource所在jar包的路径信息)。而ClassLoader类中的方法可以帮助我们动态的获取这些信息:
2、public URL getResource(String name):
  查找具有给定名称的资源。资源是可以通过类代码以与代码基无关的方式访问的一些数据(图像、声音、文本等)。并返回资源的URL对象。
3、public InputStream getResourceAsStream(String name):
  返回读取指定资源的输入流。这个方法很重要,可以直接获得jar包中文件的内容。

2.2 实现

1、在TestPath工具类中使用getClassLoader().getResourceAsStream获取资源流数据:

/**增加函数,替换getFilePath()函数,直接获取资源流数据*/
public static InputStream getFileInputStream(String fileName){
		return TestPath.class.getClassLoader().getResourceAsStream(fileName);
	}

注意:fileName如果是xml文件等,直接写文件名即可,例如原来是src/main/xxx.xml,现在直接写main/xxx.xml(src的下级目录)

2、测试打印内容:
主访问工程的main函数调用:

public static void main(String[] args) {
		try {
			InputStream fileIn = TestPath.getFileInputStream("pro/data1.txt");
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(fileIn, 
							StandardCharsets.UTF_8));
			String s = "";
			while ((s=reader.readLine())!=null) {
			    System.out.println(s);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
    }

输出结果:
2

猜你喜欢

转载自blog.csdn.net/weixin_44462773/article/details/124714272