1. 程式人生 > >java踩坑記-getResourceAsStream

java踩坑記-getResourceAsStream

mov load color () tar type 當前 blog ase

本文主要是研究下面集中方法到底誰才能真正的load到文件,你能一眼看出來嗎?

GetResourcesSample.class.getClassLoader.getResourceAsStream("main-resources-file.txt") GetResourcesSample.class.getClass().getResourceAsStream("main-resources-file.txt") GetResourcesSample.class.getResourceAsStream("main-resources-file.txt") GetResourcesSample.class.getClassLoader.getResourceAsStream("/main-resources-file.txt") GetResourcesSample.class.getClass().getResourceAsStream("/main-resources-file.txt") GetResourcesSample.class.getResourceAsStream("/main-resources-file.txt") 很暈吧,反正我是挺暈的。

目錄結構:

技術分享圖片

代碼:

public class GetResourcesSample {
    private static final String MAIN_FILE = "main-resources-file.txt";
    private static final String MAIN_FILE_WITH_SLASH = "/main-resources-file.txt";
    private static final String TEST_FILE = "test-resources-file.txt";
    private static final String TEST_FILE_WITH_SLASH = "/test-resources-file.txt";
    
private static final String ROOT_FILE = "project-root-file.txt"; private static final String ROOT_FILE_WITH_SLASH = "./project-root-file.txt"; public static void main(String[] args) { validateResult(MAIN_FILE); validateResult(MAIN_FILE_WITH_SLASH); validateResult(TEST_FILE); validateResult(TEST_FILE_WITH_SLASH); validateResult(ROOT_FILE); validateResult(ROOT_FILE_WITH_SLASH); }
private static void validateResult(String file) { InputStream inputStream1 = GetResourcesSample.class.getClass().getResourceAsStream(file); if (inputStream1 != null) { System.out.println(MessageFormat .format("GetResourcesSample.class.getClass().getResourceAsStream(\"{0}\") is not null!", file)); } InputStream inputStream2 = GetResourcesSample.class.getResourceAsStream(file); if (inputStream2 != null) { System.out.println( MessageFormat.format("GetResourcesSample.class.getResourceAsStream(\"{0}\") is not null!", file)); } InputStream inputStream3 = GetResourcesSample.class.getClassLoader().getResourceAsStream(file); if (inputStream3 != null) { System.out.println( MessageFormat.format("GetResourcesSample.class.getClassLoader().getResourceAsStream(\"{0}\") is not null!", file)); } } }

結果:

GetResourcesSample.class.getClassLoader().getResourceAsStream("main-resources-file.txt") is not null! GetResourcesSample.class.getClass().getResourceAsStream("/main-resources-file.txt") is not null! GetResourcesSample.class.getResourceAsStream("/main-resources-file.txt") is not null!

結論:

  1. Class.getResourceAsStream 最終調用的是此Class的Class Loader的getResourceAsStream來進行讀文件(有些繞,盡量理解)
  2. GetResourcesSample.class.getClass() 得到的是Class這個類的實例,它的ClassLoader是JVM的bootstrap Class Loader
  3. GetResourcesSample.class.getResourceAsStream 由於去resolve了一下name,雖然是當前class的ClassLoader,它也讀不到這個文件;除非你的文件名以“/”開頭。詳見源代碼:
        /**
         * Add a package name prefix if the name is not absolute Remove leading "/"
         * if name is absolute
         */
        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;
        }
  4. project-root-file.txt這種最後最終不被打在Jar包裏的文件,是沒有機會被讀取的,除非hard code一個文件所在的絕對路徑
  5. 把相同代碼放到UT裏面去跑,會發現UT能同時load到main和test下的文件。因為JUnit有它自己的ClassLoader,它能同時讀到main和test下的文件。

java踩坑記-getResourceAsStream