jar獲取資源文件的問題

目錄

在開發環境中運行,如eclips

在src目錄下

在非src目錄下

以jar包形式運行,linux系統

在src目錄下

在非src目錄下,但在jar包內

在jar包外

jar包訪問第三方依賴,的類路徑配置






在開發環境中運行,如eclips

在src目錄下

可以用絕對路徑和相對路徑來讀取,絕對路徑爲文件在磁盤的存放位置,這裏暫且不討論。

用相對路徑可按如下操作獲取文件資源:

File file = new File("src/main/resources/properties/basecom.properties");
InputStream in = new FileInputStream(file);

也可以通過類加載方式:

//讀取根目錄下的tmp(src/):
// 第一種方法
InputStream in = App.class.getResourceAsStream("/tmp");
// 第二種方法
InputStream in =ClassLoader.getSystemClassLoader().getResourceAsStream("tmp");
//讀取App類同級目錄下的tmp(src/space/yukai)
// 第一種方法
InputStream in = App.class.getResourceAsStream("tmp");
// 第二種方法
InputStream in =ClassLoader.getSystemClassLoader().getResourceAsStream("space/yukai/tmp");
//第三種方法
InputStream in = App.class.getResourceAsStream("/space/yukai/tmp");
//讀取MyClassloader同級目錄下的tmp(src/space/yukai/classloader):
// 第一種方法
InputStream in = App.class.getResourceAsStream("classloader/tmp");
// 第二種方法
InputStream in =ClassLoader.getSystemClassLoader().getResourceAsStream("space/yukai/classloader/tmp");
//第三種方法
InputStream in = App.class.getResourceAsStream("/space/yukai/classloader/tmp");

在非src目錄下

lib與src同級,想獲取lib目錄下的文件

File file = new File("./lib");
System.out.println(file.getAbsolutePath());
File[] listFiles = file.listFiles();

以jar包形式運行,linux系統

在src目錄下

當將工程導出jar包或war包時可用以下方法獲取

使用Class.getResource或者是ClassLoader.getResourceAsStream()將文件內容放到InputStream中

String s1 = this.getClass().getResource("/log4j.properties").getPath();

或者爲:

String s1 = CodeTest.class.getResource("/log4j.properties").getPath();

注意,使用class的getRescource時,要注意路徑前要加"/",即根目錄,此處的根目錄是src

若像如下使用:

String class_str = this.getClass().getResource("logback.xml").getPath();

則會出錯如下:

使用ClassLoader時,如下:

this.getClass().getClassLoader().getResource()
在使用ClassLoader時,路徑前面不能加"/",使用相對路徑。

public void readProperties(){
		String ss = TempTest.class.getResource("/").getPath();
		System.out.println(ss);
		String s = new File(ss).getParentFile().getPath();
		System.out.println(s);
		String system_str = System.getProperty("user.dir");
		System.out.println(system_str);
}

運行結果如下:

 

將上述readProperties函數打包爲jar包在命令行使用java -jar TempTest.jar運行時,結果如下:

 

由此可見,打包成jar包時和在ide中直接運行的結果並不一樣,所以在jar包中的class類要訪問自己jar包中的資源文件時,應該使用Class.getResource或者是getResourceAsStream放在InputStream中,再進行訪問。但是該方法只能訪問到src下的資源文件,因爲其根目錄對應的就是src,無法訪問到項目根目錄下src外的文件,如上述項目結構圖中的blackWhite中的文件無法訪問到,

關於class.getResource && classloader.getResource 的區別。

 

源碼中:Class.getResourceAsStream(String name)

public InputStream getResourceAsStream(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResourceAsStream(name);
    }
    return cl.getResourceAsStream(name);
}

上面的代碼可以看出, Class.getResourceAsStream(String name) 最終還是調用了 classloader.getResourceAsStream(String name) 。但是兩者還是有一些區別的,注意 name =resolveName(name)這一行,Class.getResourceAsStream(String name)在這裏做了一些處理:Class.resolveName(String name)

通過測試類進行測試:

public class App {
    public static void main(String[] args) {
    System.out.println("App.class.getClassLoader().getResource(\"\") : " +             
        App.class.getClassLoader().getResource(""));
    System.out.println("App.class.getClassLoader().getResource(\"/\") : " + 
        App.class.getClassLoader().getResource("/"));
    System.out.println("App.class.getResource(\"\") : " + App.class.getResource(""));
    System.out.println("App.class.getResource(\"/\") : " + App.class.getResource("/"));
    }
}

結果如下:

App.class.getClassLoader().getResource("") : 
              file:/D:/workspace/eclipse/cluster/TestClassloader/bin/
App.class.getClassLoader().getResource("/") : null
App.class.getResource("") : 
               file:/D:/workspace/eclipse/cluster/TestClassloader/bin/space/yukai/
App.class.getResource("/") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/

calssloder.getResource("")方法返回了classpath根路徑(eclipse工程中,編譯生成的類文件存放在/bin目錄下);

calssloder.getResource("/")方法返回null,說明calssloder.getResource不支持以"/"開頭的參數;

class.getResource("")方法返回了App.class所在的路徑;

class.getResource("/")與calssloder.getResource("")表現一致,返回了classpath的根路徑

 

在非src目錄下,但在jar包內

如圖想打jar包後能繼續訪問lib中的json文件,可以用JarFile類來實現。

package com.test.jar;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ReadSource {
	public static void main(String[] args) throws Exception {
		String path = ReadSource.class.getProtectionDomain().getCodeSource().getLocation().getPath();//獲取jar包的絕對路徑
		path = java.net.URLDecoder.decode(path, "UTF-8");//轉換處理中文及空格,但是如果路徑中包含中文,就會變成帶“%xx%xx”格式的字符串。所以應該這樣寫纔對:
		System.out.println("path: "+path);
		JarFile localJarFile = new JarFile(new File(path));
		 Enumeration<JarEntry> entries = localJarFile.entries();
		 while (entries.hasMoreElements()) {
             JarEntry jarEntry = entries.nextElement();
             System.out.println(jarEntry.getName());
             String innerPath = jarEntry.getName();
             if(innerPath.contains(".json")&& !innerPath.contains("jar")){
                 InputStream inputStream = 
                        ReadSource.class.getClassLoader().getResourceAsStream(innerPath);
                 BufferedReader br = new BufferedReader(new 
                        InputStreamReader(inputStream));         
                 String line="";
                 while((line=br.readLine())!=null){
                       System.out.println(innerPath+"內容爲:"+line);
                 }
             }
         }
	}
}

結果:

在jar包外

比如在jar包同級目錄下有名爲testInfo的文件夾,

File file = new File("./testInfo");可獲取該文件夾對象。

file.getAbsolutePath();可獲取該文件夾對象的絕對路徑。

jar包訪問第三方依賴,的類路徑配置

 

手動配置MANITAST.MF中的class_path配置,即需要的第三方jar包

打包可執行jar包時,MANIFEST.MF總是個讓人頭疼的東西,經常出現這種那種問題。

 

一個例子:

Manifest-Version: 1.0
Main-Class: test.Main
Class-Path: ./ ./lib/commons-collections-3.2.jar ./lib/commons-dbcp-1.2.2.jar ./lib/commons-lang-2.3.jar ./lib/commons-logging-1.1.jar

各部分解釋:

Manifest-Version MF文件版本號

Main-Class 包含main方法的類

Class-Path 執行這個jar包時的ClassPath

 

以下是需要注意的各個要點:

  1. Manifest-Version、Main-Class和Class-Path後面跟着一個英文的冒號,冒號後面必須跟着一個空格,然後纔是版本號、類和ClassPath。
  2. Class-Path中的各項應使用空格分隔,不是逗號或分號。 
  3. Class-Path中如果有很多項,寫成一行打包的時候會報錯line too long,這時需要把Class-Path分多行寫。注意:從第二行開始,必須以兩個空格開頭,三個以上我沒試過,不過不用空格開頭和一個空格開頭都是不行的,我已經試過了。
  4. Class-Path寫完之後最後一定要有一個空行

5. jar包內有些配置文件想放在jar包外面,比如文件config.properties:如果這個文件是以路徑方式載入的,比如new file("./config/config.properties"),那麼將config.properties放在jar包相同目錄下的config目錄下即可,也就是說“./”路徑等價於jar包所在目錄;如果這個文件是以ClassPath下的文件這種方式載入的,比如在Spring中載入classpath:config.properties,則在MF文件的配置文件的ClassPath中添加“./”,然後將這個配置文件與jar包放在同一個目錄即可,當然也可以在MF文件的配置文件的ClassPath中添加“./config/”,然後把配置文件都放在jar包相同目錄下的config目錄下。

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章