介绍在java中的几种资源读取方式

Class下有两个方法:
1:getResource
    它的源码是:
 public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }
 其中resolveName内容:
 private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }
如果传入的路径有 /  那么取 /后面的内容,如果没有 /  找到调用这个方法的class的类限定名(包+类名),取类名前面的包,将 . 转换成 / 
 ClassLoader cl = getClassLoader0();    cl.getResource(name); 应该是在工程项目下加载资源。
 ClassLoader.getSystemResource(name) 当class。为系统类库时,就会根据这个方法在系统类库下找。
小结:其实不管路径前面有没有/ 他们会做一个相同的事情,就是根据加载器,定位到classpath下,然后如果有斜杠那么去掉斜杠,作为classpath的资源路径。如果没有斜杠,那么根据加载的类,得到它的包,指明是classpath+包  ,在这个路径下找资源

2:getResourceAsStream
这个方法和上边的方法实现的寻找资源方式是一样的。就不多讲了。

但是这两种有个值得注意的注意的地方。博主eclipse的目录中带有空格。结构,getResource()找不到资源,而且getResourceAsStream()却能找到。非常的郁闷。这其中的原因就是因为getResource()返回的是URL 这个类对空格,中文处理后产生的路径会产生乱码。这导致路径出错了。解决办法很简单。URLDecoder.decode(path,"utf8");   这样就可以通过了,由于对乱码这一块还是非常薄弱,所以就不多加深入了

getClassLoader两个方法
1:getResource()
public ClassLoader getClassLoader() {
        ClassLoader cl = getClassLoader0();
        if (cl == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader ccl = ClassLoader.getCallerClassLoader();
            if (ccl != null && ccl != cl && !cl.isAncestor(ccl)) {
                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
        return cl;
    }
public URL getResource(String name) {
	URL url;
	if (parent != null) {
	    url = parent.getResource(name);
	} else {
	    url = getBootstrapResource(name);
	}
	if (url == null) {
	    url = findResource(name);
	}
	return url;
    }
这里得到加载器,直接去加载classpath下的资源,所以getClassLoader.getResource("xxx")  xxx这里就是classpath下的资源路径。这里值得注意的是:xxx开头不能带/.否则资源找不到,这就是什么原因 关键就是 getBootstrapResource(name)这一块了,sun公司没有提供源码。
2:  getResourceAsStream();
资源路径处理的方式和上边一样,就不多说了。

先看看下面的代码

public static void main(String[] args) throws IOException {
		System.out.println(System.getProperty("user.dir"));
		File flie= new File("bin/file.txt");
		FileInputStream fis = new FileInputStream(flie);
		byte[] cache = new byte[1024];
		if(fis.read(cache)!=-1){
			System.out.println(new String(cache));
		}
	}

该类是在package1包下 file.txt是在src目录下。

在J2EE的一些资源的定位中我们将没有加 / 的路径 作为当前目录下的资源。那么这里 new File("bin/file.txt“)  照理说是在package1下 bin文件夹下的file.txt

而实际在I这里指的就是bin文件夹下的file.txt。 IDE环境中相对路径是工程的根目录。但是如果实在控制台执行那么上边的程序会报FileNotFoundException 所以需要用到绝对路径了.class.getResource()/getResourceAsStream()等读取


接下来探索的话题是jar资源的加载。
先看看下面的代码
public static void main(String[] args) throws IOException {
		System.out.println(System.getProperty("user.dir"));
		File flie= new File("bin/file.txt");
		FileInputStream fis = new FileInputStream(flie);
		byte[] cache = new byte[1024];
		if(fis.read(cache)!=-1){
			System.out.println(new String(cache));
		}
	}
该类是在package1包下 file.txt是在src目录下。
在J2EE的一些资源的定位中我们将没有加 / 的路径 作为当前目录下的资源。那么这里 new File("bin/file.txt“)  照理说是在package1下 bin文件夹下的file.txt
而实际在I这里指的就是bin文件夹下的file.txt。 IDE环境中相对路径是工程的根目录。但是如果实在控制台执行那么上边的程序会报FileNotFoundException 所以需要用到绝对路径了.class.getResource()/getResourceAsStream()等读取


jar的资源访问:

一个有意思的main
我把上面的程序打成了一个jar导入到另外一个工程, 上面的main可以在这个被工程下的类调用,这个还第一次知道 &_^   
当然上边的资源会报FileNotFoundException  不是在没打成jar包前测试过了吗,好好的,怎么打成jar后就找不到资源了呢。这就是我当前要探索的东西了。
我在功能找了那个导入的jar包发现bin不见了, file.txt直接在jar包的根目录下,那么代码中的bin/file.txt当然是无法定位。 我在新的工程src下加入了一个file.txt文件额,这回找到了。看来jar中的资源路径,会在当前的工程中去找额。发现问题,就要针对这个问题去解决,如何解决,我想到,既然没有bin,那么我用绝对路径写死它。file:/..test.jar/file.txt. 不行吗? 抱歉。还真不行。test.jar这个后缀名都有了,果断是一个文件,难道要访问文件下的资源?
好吧。没辙了吧。这里就要用到上边说将的getResource/getResourceAsStream来加载了。当然getClassLoader.getResource和getClassLoader.getResourceAsStream也是一样的效果。在调用jar包的类时,都要用加载器加载这个类,加载器会记录关于这个类的信息,我们就可以通过这点取到资源路径。
public void getResource() throws IOException {
		URL url = ReadResource.class.getResource("/file.txt");
		String path = url.getPath();
		path = URLDecoder.decode(path,"utf8");
		BufferedReader br1 = new BufferedReader(new FileReader(path));
		System.out.println(br1.readLine());
	}
将这个ReadResource类打成一个jar,导入到Ex项目下。运行,就能准确的读取
我在getResource()中加了一行System.out.println(path); 在Ex中运行,得到的路径就是:/F:/Workspaces/Eclipse 3.1/Ex/bin/file.txt
这个file.txt就是jar中的资源了。
 
 

现在我有个很迷惑的地方,这段代码我从xwork中找出来的。

public static Iterator<URL> getResources(String resourceName, Class callingClass, boolean aggregate) throws IOException {

         AggregateIterator<URL> iterator = new AggregateIterator<URL>();

         iterator.addEnumeration(Thread.currentThread().getContextClassLoader().getResources(resourceName));

         if (!iterator.hasNext() || aggregate) {
             iterator.addEnumeration(ClassLoaderUtil.class.getClassLoader().getResources(resourceName));
         }

         if (!iterator.hasNext() || aggregate) {
             ClassLoader cl = callingClass.getClassLoader();

             if (cl != null) {
                 iterator.addEnumeration(cl.getResources(resourceName));
             }
         }

         if (!iterator.hasNext() && (resourceName != null) && ((resourceName.length() == 0) || (resourceName.charAt(0) != '/'))) { 
             return getResources('/' + resourceName, callingClass, aggregate);
         }

         return iterator;
     }

如果resourceName没有带斜杠,那么不管通过上边那种方式获得资源他们都是一样的。那么何必多此一举呢?如果带斜杠,那么就像之前说的,资源是找不到的返回一个null。但是这边还是通过这种方式来。这是什么意思了?留着以后补充吧。







你可能感兴趣的:(介绍在java中的几种资源读取方式)