1. 程式人生 > 實用技巧 >java中Class.getResourceAsStream()和ClassLoader.getResourceAsStream()的區別

java中Class.getResourceAsStream()和ClassLoader.getResourceAsStream()的區別

簡介

Class.getResourceAsStream()和ClassLoader.getResourceAsStream()方法都是從專案中讀取檔案,但很容易被搞混。

ClassLoader

public class Client2 {

  public static void main(String[] args) {
    //從classpath下查詢
    InputStream in = Client2.class.getClassLoader().getResourceAsStream("files/asd.txt");
    if (in == null) {
      return;
    }
    try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      String line = null;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

我們將檔案放到classpath下,ClassLoader會直接從classpath的根目錄下查詢檔案,
輸出結果為

this is a test file2

Class

public class Client3 {

  public static void main(String[] args) {
    InputStream in = Client3.class.getResourceAsStream("/files/asd.txt");
    if (in == null) {
      return;
    }
    try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      String line = null;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

通過Class也可以讀到classpath下的檔案,我們需要以/開頭。

public class Client4 {

  public static void main(String[] args) {
    InputStream in = Client4.class.getResourceAsStream("abc.txt");
    if (in == null) {
      return;
    }
    try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      String line = null;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

我們將檔案放到當前類所在的包下,這個時候不能以/開頭,直接相對路徑就可以。

原始碼分析

public final
    class Class<T> implements java.io.Serializable,
                              java.lang.reflect.GenericDeclaration,
                              java.lang.reflect.Type,
                              java.lang.reflect.AnnotatedElement {
	public InputStream getResourceAsStream(String name) {
        	name = resolveName(name);
        	ClassLoader cl = getClassLoader0();
        	if (cl==null) {
            		// A system class.
            		return ClassLoader.getSystemResourceAsStream(name);
        	}
   		//實際上還是呼叫ClassLoader的getResourceAsStream()方法
        	return cl.getResourceAsStream(name);
    	}
	//解析檔案路徑,如果以/開頭,擷取/之後的,不以/開頭,當做相對路徑,新增包的路徑
	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;
    }

}

總結

ClassLoader從classpath下查詢,不能以/開頭,不能相對路徑,Class如果以/開頭,直接擷取/之後的路徑,不以/開頭,轉換成包含package的全路徑,內部還是呼叫的ClassLoader的方法。