`

如何用Spring读取JAR中的文件

 
阅读更多
   
使用如下方式读取JAR中的文件出错

   类路径下放了一个jarfile.jar,如下所示:

   如上所示,com/yyy/1.txt放在jarfile.jar中。
   我原来使用如下的方式读取这个JAR中的文件:
@Test
public void usingSpringMethod() throws Throwable {
	PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
	Resource[] resources = patternResolver.getResources("com/yyy/1.txt");
	if (resources != null && resources.length > 0) {
		File file = resources[0].getFile();//<---①
		FileInputStream inputStream = new FileInputStream(file);
		InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
		char[] data = new char[100];
		inputStreamReader.read(data);
		assertEquals((new String(data)).trim(), "ddddd");
	}
}

   运行后,抛出异常,其问题出在①处,原因是:JAR中的文件无法以File方式返回,而只有在文件系统中的类资源才可以以File的形式返回。
   但是,不管是文件系统中的类资源,还是JAR中的类资源文件,都可以以流的形式读取,因此,如上的代码调整一下就正常了:
@Test
public void usingSpringMethod() throws Throwable {
	PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
	Resource[] resources = patternResolver.getResources("com/yyy/1.txt");//<--②
	if (resources != null && resources.length > 0) {
		InputStreamReader inputStreamReader = new InputStreamReader(resources[0].getInputStream());//<---①
		char[] data = new char[100];
		inputStreamReader.read(data);
		assertEquals((new String(data)).trim(), "ddddd");
	}
}

   上面①处,使用resource[0].getInputStream()代替原来的
引用
resources[0].getFile()
。当然,②处的资源路径表达式,可以使用Spring的其它方式表示:
   方式1:
Resource[] resources = patternResolver.getResources("classpath:com/yyy/1.txt");

   方式2:
Resource[] resources = patternResolver.getResources("classpath*:com/yyy/1.txt");


直接原生的JDK方式读取
   Spring对资源路径的表达方式非常灵活,这是我们首选使用Spring加载资源的原因。当然,使用JDK原生的ClassLoader也可以加载JAR中的资源文件,如下所示:
    
@Test
public void usingJDKMethod() throws Throwable {
	URL url = getClass().getClassLoader().getResource("com/yyy/1.txt");//<--①
	InputStreamReader inputStreamReader = new InputStreamReader(url.openStream());
	char[] data = new char[100];
	inputStreamReader.read(data);
	assertEquals((new String(data)).trim(), "ddddd");
}

    唯一的限制是,在①处不再支持classpath:或classpath*:的前缀了。
  • 大小: 11.8 KB
3
0
分享到:
评论
4 楼 youjianbo_han_87 2012-10-09  
您的Spring 3.X 这本书定价对于学生一族太贵了,
3 楼 stamen 2012-04-14  
jinnianshilongnian 写道
你没贴全内容?

这个跟jar包没关系,跟classpath有关

之前我总结过下边四种方式

1、获取本地文件系统资源(不推荐使用,最后没招时使用)
File
2、获取当前类所在目录下的资源
MyServlet.class.getResourceAsStream(name)
3、获取Classpath资源
Thread.currentThread().getContextClassLoader().getResourceAsStream(name)

getClass().getClassLoader.getResourceAsStream(name)
4、读取web上下文下资源
ServletContext.getResourceAsStream(name)

//这个只返回文件系统类路径资源,不会包含jar包路径
Enumeration<URL> urls = new MyTest().getClass().getClassLoader().getResources("");

//这个即返回文件系统类路径资源,也包含jar包路径
Enumeration<URL> urls = new MyTest().getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");


   在“com.springsource.cn.sf.cglib-2.2.0.jar”里包含“asm-license.txt”文件,对于使用“classpath*: asm-*.txt”进行通配符方式加载资源将什么也加载不了“asm-license.txt”文件,注意一定是模式路径匹配才会遇到这种问题。这是由于“ClassLoader”的“getResources(String name)”方法的限制,对于name为“”的情况将只返回文件系统的类路径,不会包换jar包根路径。

@Test  
public void testClasspathAsteriskPrefixLimit() throws IOException {  
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();      //将首先通过ClassLoader.getResources("")加载目录,  
    //将只返回文件系统的类路径不返回jar的跟路径  
    //然后进行遍历模式匹配  
    Resource[] resources = resolver.getResources("classpath*:asm-*.txt");  
    Assert.assertTrue(resources.length == 0);  
    //将通过ClassLoader.getResources("asm-license.txt")加载  
    //asm-license.txt存在于com.springsource.net.sf.cglib-2.2.0.jar  
    resources = resolver.getResources("classpath*:asm-license.txt");  
    Assert.assertTrue(resources.length > 0);       
    //将只加载文件系统类路径匹配的Resource  
    resources = resolver.getResources("classpath*:LICENS*");  
    Assert.assertTrue(resources.length == 1);  
}  


对于“resolver.getResources("classpath*:asm-*.txt");”,由于在项目“resources”目录下没有所以应该返回0个资源;“resolver.getResources("classpath*:asm-license.txt");”将返回jar包里的Resource;“resolver.getResources("classpath*:LICENS*");”,因为将只返回文件系统类路径资源,所以返回1个资源。

因此在通过前缀“classpath*”加载通配符路径时,必须包含一个根目录才能保证加载的资源是所有的,而不是部分。

http://jinnianshilongnian.iteye.com/blog/1416322

   分析得非常好,特别是对直接放在根路径下的文件的分析,这是很容易出错的地方。
2 楼 stamen 2012-04-14  
呵呵,真是没有写全,今天补上了。
1 楼 jinnianshilongnian 2012-04-13  
你没贴全内容?

这个跟jar包没关系,跟classpath有关

之前我总结过下边四种方式

1、获取本地文件系统资源(不推荐使用,最后没招时使用)
File
2、获取当前类所在目录下的资源
MyServlet.class.getResourceAsStream(name)
3、获取Classpath资源
Thread.currentThread().getContextClassLoader().getResourceAsStream(name)

getClass().getClassLoader.getResourceAsStream(name)
4、读取web上下文下资源
ServletContext.getResourceAsStream(name)

//这个只返回文件系统类路径资源,不会包含jar包路径
Enumeration<URL> urls = new MyTest().getClass().getClassLoader().getResources("");

//这个即返回文件系统类路径资源,也包含jar包路径
Enumeration<URL> urls = new MyTest().getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");


   在“com.springsource.cn.sf.cglib-2.2.0.jar”里包含“asm-license.txt”文件,对于使用“classpath*: asm-*.txt”进行通配符方式加载资源将什么也加载不了“asm-license.txt”文件,注意一定是模式路径匹配才会遇到这种问题。这是由于“ClassLoader”的“getResources(String name)”方法的限制,对于name为“”的情况将只返回文件系统的类路径,不会包换jar包根路径。

@Test  
public void testClasspathAsteriskPrefixLimit() throws IOException {  
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();      //将首先通过ClassLoader.getResources("")加载目录,  
    //将只返回文件系统的类路径不返回jar的跟路径  
    //然后进行遍历模式匹配  
    Resource[] resources = resolver.getResources("classpath*:asm-*.txt");  
    Assert.assertTrue(resources.length == 0);  
    //将通过ClassLoader.getResources("asm-license.txt")加载  
    //asm-license.txt存在于com.springsource.net.sf.cglib-2.2.0.jar  
    resources = resolver.getResources("classpath*:asm-license.txt");  
    Assert.assertTrue(resources.length > 0);       
    //将只加载文件系统类路径匹配的Resource  
    resources = resolver.getResources("classpath*:LICENS*");  
    Assert.assertTrue(resources.length == 1);  
}  


对于“resolver.getResources("classpath*:asm-*.txt");”,由于在项目“resources”目录下没有所以应该返回0个资源;“resolver.getResources("classpath*:asm-license.txt");”将返回jar包里的Resource;“resolver.getResources("classpath*:LICENS*");”,因为将只返回文件系统类路径资源,所以返回1个资源。

因此在通过前缀“classpath*”加载通配符路径时,必须包含一个根目录才能保证加载的资源是所有的,而不是部分。

http://jinnianshilongnian.iteye.com/blog/1416322

相关推荐

Global site tag (gtag.js) - Google Analytics