java 檔案處理總結
前言:
一直以來,飽受檔案路徑的困惑,自己翻閱印象筆記中記錄的此類記錄,發現很多都是雜亂,根本不能簡單話的解釋這個問題。本篇的目的是總結以前的筆記,加上自己測試的例子,能明白準確的記錄下這個問題。內容的話僅包含常見的java程式讀取檔案,不包含java web和jsp的讀取檔案方式。
問題一:Class.getResource和ClassLoader.getResource的分析
我經常寫讀取property結尾的key=value的檔案,以一個PropertiesUtil工具類為例,程式碼如下:
public class PropertiesUtil {
private static Properties scheduleProp;
private static Properties urlProp;
private static Properties daoProp;
private static Properties executorProp;
private static Properties serviceProp;
public static Properties getProSchedule() {
try {
if(scheduleProp==null) { scheduleProp = new Properties(); scheduleProp.load(PropertiesUtil.class.getClassLoader().getResourceAsStream("scheduletask.properties"));
}
} catch (IOException e) {
e.printStackTrace();
}
return scheduleProp;
}
這裡的ClassLoader的getResourceAsStream返回的是InputStream流,我們需要關注的是傳入的String name。首先,Java中的getResourceAsStream有以下幾種:
1. Class.getResourceAsStream(String path) : path 不以’/’開頭時預設是從此類所在的包下取資源,以’/’開頭則是從ClassPath根下獲取。其只是通過path構造一個絕對路徑,最終還是由ClassLoader獲取資源。
2. Class.getClassLoader.getResourceAsStream(String path) :預設則是從ClassPath根下獲取,path不能以’/’開頭,最終是由ClassLoader獲取資源。
函式的原始碼
java.lang.ClassLoader.getResourceAsStream()
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}
java.lang.ClassLoader.getResource()
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;
}
java.lang.Class.getResourceAsStream()
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);
}
java.lang.Class.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);
}
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;
}
PS: 這裡強調一下,實際上的Class的函式是呼叫ClassLoader的方法。另外為什麼class的可以(“/”),classLoader為什麼不可以,resolveName這個函式裡面就可以看出來了。
問題二:File和FileInputStream路徑分析
以TestFile程式碼展示用例:
@Test
public void test() throws IOException {
String path=this.getClass().getClassLoader().getResource("1.txt").getPath();
String filePath=this.getClass().getResource("/1.txt").getFile();
System.out.println(path);
System.out.println(filePath);
File file=new File(path);
File file1=new File("/1.txt");
File file2=new File("1.txt");
String path1=file1.getAbsolutePath();
String path2=file2.getAbsolutePath();
System.out.println(path1);
System.out.println(path2);
ioRead(file);
nioRead(file);
ioRead(path);
}
public void ioRead(File file) throws IOException{
FileInputStream in =new FileInputStream(file);
byte[] b=new byte[1024];
in.read(b);
System.out.println(new String(b));
}
public void nioRead(File file)throws IOException{
FileInputStream in=new FileInputStream(file);
FileChannel channel=in.getChannel();
ByteBuffer buffer=ByteBuffer.allocate(1024);
channel.read(buffer);
byte[]b=buffer.array();
System.out.println(new String(b));
}
public void ioRead(String file) throws IOException{
FileInputStream in =new FileInputStream(file);
byte[] b=new byte[1024];
in.read(b);
System.out.println(new String(b));
}
public void nioRead(String file)throws IOException{
FileInputStream in=new FileInputStream(file);
FileChannel channel=in.getChannel();
ByteBuffer buffer=ByteBuffer.allocate(1024);
channel.read(buffer);
byte[]b=buffer.array();
System.out.println(new String(b));
}
程式排版,檔案排版和結果截圖:
如果把 File file2=new File(“1.txt”); 改為File file2=new File(“test/1.txt”);
結果截圖如下:
- 根據上面的截圖,我們可以知道File和FileInputStream的相對路徑是相當於工程檔案learnnetty為基準,而絕對路徑是以檔案系統為基準的。
- 對於class和classloader得到的URL資訊,是基於生成bin目錄下的class。相對路徑是class的當前目錄,而絕對路徑是以bin為根目錄。
PS:這裡classloader和class的getresource的函式不同可以參考第一個問題。