1. 程式人生 > >Java檔案讀取 jar包內檔案讀取。

Java檔案讀取 jar包內檔案讀取。

最近遇到一些Jar包內外配置檔案讀取的問題。索性自己測試總結一下,與大家分享。

主要是關於ClassLoader.getResource和Class.getResource方法路徑區別的問題。

1. 絕對路徑檔案讀取,最簡單,最直接的方式

	/**
	 * 從絕對路徑讀取檔案,最基本的檔案讀取方式
	 * 
	 * @author lihzh
	 * @data 2012-4-11 下午9:33:44
	 */
	@Test
	public void testGetFileFromAbsolutePath() {
		String dirPathNotUnderClasspath = "D:\\workspace-home\\JavaDemo\\conf"
; File dirFile = new File(dirPathNotUnderClasspath); AssertDirFile(dirFile); } /** * 對資料夾型別檔案的斷言 * * @param dirFile * @author lihzh * @data 2012-4-11 下午9:49:14 */ private void AssertDirFile(File dirFile) { // 檔案存在 Assert.assertTrue(dirFile.exists()); // 是絕對路徑 Assert.assertTrue
(dirFile.isAbsolute()); // 是個資料夾 Assert.assertTrue(dirFile.isDirectory()); // 獲取資料夾下所有檔案 File[] files = dirFile.listFiles(); // 下面有檔案 Assert.assertNotNull(files); // 且只有一個 Assert.assertEquals(1, files.length); // 檔名匹配 Assert.assertEquals("test.properties", files[0].getName()); }

2. 相對於執行編譯命令路徑的方式讀取

	/**
	 * 從相對路徑讀取檔案,相對於編譯路徑,在Eclipse中即為工程所在根目錄。 本質還是絕對路徑讀取。
	 * 
	 * @author lihzh
	 * @data 2012-4-11 下午9:51:10
	 */
	@Test
	public void testGetFileFromRelativePath() {
		String dirPath = System.getProperty("user.dir") + "\\conf";
		File dirFile = new File(dirPath);
		AssertDirFile(dirFile);
	}

3. 用URI構造本地檔案讀取

   /**
	 * 構造URI/URL格式的檔案路徑,讀取本地檔案
	 * 
	 * @author lihzh
	 * @throws URISyntaxException
	 * @throws MalformedURLException
	 * @data 2012-4-11 下午10:25:00
	 */
	@Test
	public void testGetFileFromURIPath() throws URISyntaxException,
			MalformedURLException {
		// 直接用URI構造, 由於URI和URL可以互轉,所以如果為URL直接用URL.toURI轉換成URI即可
		URI uri = new URI("file:/D:/workspace-home/JavaDemo/conf/");
		File dirFile = new File(uri);
		AssertDirFile(dirFile);
	}

特別說明:</span>用URI/URL的方式構造路徑是個人比較推薦的,可以解決一些路徑讀取的問題。例如:Spring會對URI/URL格式的路徑進行專有處理可以準確定位的位置,而直接使用絕對路徑,在用Classpath和FileSystem兩種不同的初始化方式下,可能會出現錯誤。

4. 利用ClassLoader讀取Jar包內部檔案

   /**
	 * 從依賴的Jar包中讀取檔案, Jar包內的檔案是無法用File讀取的,只能用Stream的方式讀取。
	 * 
	 * @author lihzh
	 * @throws URISyntaxException
	 * @throws IOException
	 * @data 2012-4-11 下午11:07:58
	 */
	@Test
	public void testGetFileFromJarInClassPath() throws URISyntaxException,
			IOException {
		Enumeration<URL> urls = this.getClass().getClassLoader().getResources("conf/test.properties");
		URL url = this.getClass().getClassLoader().getResource("conf/test.properties");
		Assert.assertTrue(urls.hasMoreElements());
		Assert.assertNotNull(url);
		// 注意兩種不同調用方式的路徑的區別,此處如果不以'/' 開頭,會被當作相對於當前類所在的包類處理,自然無法找到。
		// 因為在Class的getResource方法的開頭,有一個resolveName方法,處理了傳入的路徑格式問題。而ClassLoader類裡的
		// getResource和getResources均無此處理。使用時候需要用心。
		URL clzURL = this.getClass().getResource("/conf/test.properties");
		URL nullURL = this.getClass().getResource("conf/test.properties");
		Assert.assertNotNull(clzURL);
		Assert.assertNull(nullURL);
		URL thisClzURL = this.getClass().getResource("");
		Assert.assertNotNull(thisClzURL);
		// 開始讀取檔案內容
		InputStream is = this.getClass().getResourceAsStream("/conf/test.properties");
		Properties props = new Properties();
		props.load(is);
		Assert.assertTrue(props.containsKey("test.key"));
		Assert.assertEquals("thisIsValue", props.getProperty("test.key"));
	}

5. 讀取Jar內某路徑下的所有檔案

	/**
	 * 從ClassPath中的Jar包讀取某資料夾下的所有檔案
	 * 
	 * @author lihzh
	 * @throws IOException 
	 * @data 2012-4-13 下午10:22:24
	 */
	@Test
	public void testGetFilesFromJarInClassPathWithDirPath() throws IOException {
		String dirPath = "conf/";
		URL url = this.getClass().getClassLoader().getResource(dirPath);
		Assert.assertNotNull(url);
		String urlStr = url.toString();
		// 找到!/ 截斷之前的字串
		String jarPath = urlStr.substring(0, urlStr.indexOf("!/") + 2);
		URL jarURL = new URL(jarPath);
		JarURLConnection jarCon = (JarURLConnection) jarURL.openConnection();
		JarFile jarFile = jarCon.getJarFile();
		Enumeration<JarEntry> jarEntrys = jarFile.entries();
		Assert.assertTrue(jarEntrys.hasMoreElements());
		Properties props = new Properties();
		while (jarEntrys.hasMoreElements()) {
			JarEntry entry = jarEntrys.nextElement();
			// 簡單的判斷路徑,如果想做到像Spring,Ant-Style格式的路徑匹配需要用到正則。
			String name = entry.getName();
			if (name.startsWith(dirPath) && !entry.isDirectory()) {
				// 開始讀取檔案內容
				InputStream is = this.getClass().getClassLoader().getResourceAsStream(name);
				Assert.assertNotNull(is);
				props.load(is);
			}
		}
		Assert.assertTrue(props.containsKey("test.key"));
		Assert.assertEquals("thisIsValue", props.getProperty("test.key"));
		Assert.assertTrue(props.containsKey("test.key.two"));
		Assert.assertEquals("thisIsAnotherValue", props.getProperty("test.key.two"));
	}

對於不在ClassPath下的Jar包的讀取,當作一個本地檔案用JarFile讀取即可。路徑可使用絕對路徑。或者用上面的url.getConnection也可以處理。這裡不再實現。 希望對你有所幫助。