1. 程式人生 > >java 檔案處理總結

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的函式不同可以參考第一個問題。