標籤:nat 比較 except down 允許 額外 created 時間戳記 readonly
轉載請註明源出處:http://www.cnblogs.com/lighten/p/6992043.html
1.前言
在講解Java的檔案流之前,先來認識一下Java的檔案系統的實現。值得一提的是,Java8與Java7相比,對這一塊做了一些改動,接下來會進行對比介紹,但主要還是以Java8為主。
1.1 Java7與Java8不同之處概覽
首先,Java8多了一個DefaultFileSystem,但少了一個Win32FileSystem類,其次兩者的抽象父類FileSystem有些許區別。Java7的抽象父類有一個靜態native方法,FileSystem getFileSystem();
而Java8沒有。在File類檔案我們可以看到,Java7擷取電腦主機的檔案系統就是通過FileSystem.getFileSystem();而Java8則是通過DefaultFileSystem.getFileSystem();
這個WinNTFileSystem是兩個版本都有的一個類,但實現不一樣,由於Java7存在Win32FileSystem,其WinNTFileSystem類是繼承自Win32FileSystem,Java8沒有這個類,所以其是直接繼承抽象父類FileSystem。從這裡我們也可以看出區別了,Java7是通過native方法來選擇主機的檔案系統實作類別執行個體。但是Java8隻有WinNTFileSystem一個實作類別,沒有Win32FileSystem的,因此就是直接返回一個WinNTFileSystem執行個體。後面將比較WinNTFileSystem在兩個版本的不同之處。
2.WinNTFileSystem
FileSystem中定義了許多的抽象方法,具體如下:
涉及到檔案系統的查詢,添加刪除都是native方法,具體如下:
private native String getDriveDirectory(int drive); //擷取磁碟目錄,A~Z盤符private native String canonicalize0(String path) throws IOException; // 正常化檔案路徑private native String canonicalizeWithPrefix0(String canonicalPrefix, String pathWithCanonicalPrefix) throws IOException; // 這個也是正常化,不過其假定之前的路徑都是規範的,只需要規範路徑最後一個元素// 一些檔案的操作,檔案資訊的讀取,刪除建立目錄及檔案許可權等等public native int getBooleanAttributes(File f); public native boolean checkAccess(File f, int access);public native long getLastModifiedTime(File f);public native long getLength(File f);public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);public native boolean createFileExclusively(String path) throws IOException;public native String[] list(File f);public native boolean createDirectory(File f);public native boolean setLastModifiedTime(File f, long time);public native boolean setReadOnly(File f);private native boolean delete0(File f);private native boolean rename0(File f1, File f2);private static native int listRoots0();private native long getSpace0(File f, int t);private static native void initIDs();
Java7與Java8針對於檔案的一些操作方法,在WinNTFileSystem大致相同,不過Java7是將其實現在Win32FileSystem類中。雖說是大致相同,但是還是有些許差別。Win32FileSystem擷取磁碟使用大小如下:
兩個版本的WinNTFileSystem的實現卻是一樣的。
這裡為什麼不需要相容Win32就不清楚了,或許是在使用時判斷過了,或許是native方法getSpace0的實現方法不同了。而除了這個方法,兩者的這個WinNTFileSystem都實現都是一樣的,Java7的Win32FileSystem就是一個getSpace與WinNTFileSystem,這也難怪移除了這個類,只使用WinNTFileSystem這個類了。
由於大部分方法都是些native方法,調用這些方法的方法實現也比較簡單,這裡就不進行說明了,直接看源碼就很明白了。這裡簡單介紹一下檔案路徑的處理過程。
1.public String canonicalize(String path);
(1)判斷path長度:
長度為兩位,格式是字母:,則返回大寫字母:,比如C:
長度為三位,格式是字母:\\,則返回大寫字母:\\,如C:\\
(2)判斷設定是否需要緩衝路徑:
不需要,調用native方法canonicalize0
需要,擷取緩衝cache,存在就直接返回。不存在:
(a)如果使用緩衝的路徑首碼,通過parentOrNull擷取檔案的父路徑,沒有則為null。如果父路徑不為空白,取緩衝prefixCache,緩衝為空白,就調用canonicalizeWithPrefix,注意這裡放入的緩衝是cache,這個結果就是我們需要的整個路徑格式化結果。
(b)如果結果還是null,就使用navtive方法的canonicalize0擷取格式化路徑。放入cache緩衝。注意,如果需要緩衝首碼,並且a步驟解析的父路徑不為空白,就重新通過格式化後的路徑擷取父檔案,存在且格式化後的路徑也是一個檔案存在且不是目錄,就將結果存入prefixCache。
這個解析過程看過去很麻煩,為什麼不直接調用canonicalize0方法。主要是通過使用緩衝,可以改進啟動的效能。值得注意的是,a步驟和b步驟放入cache中的索引值寫法是不一樣的,但是結果是一致的,cache處理的是相同path的格式化路徑,索引值就是傳入的path,prefixCache處理的是父目錄目錄的格式化路徑,取出來的是父目錄的格式化路徑,確保與native演算法canonicalize_md.c中的結果一致,進行了相應的轉換處理,所以源碼看過去有些繁瑣。
3.File
File類有四種構造方法:
不管是哪種方式,最終都是要初始化兩個參數:
下面這些檔案方式,都是使用了FileSystem的與路徑處理相關的方法:
而剩下的所有方法,都與FileSystem的native方法相關了,沒有太多介紹的必要。唯一有點意思的就是deleteOnExit()方法,其實現與DeleteOnExitHook類相關,這個類最後會介紹。
4.其它相關類4.1 ExpiringCache
第2節講到過擷取路徑的標準字串時使用到了緩衝,這個緩衝就是ExpiringCache類,這是一個帶時效的緩衝,實現關鍵就在於初始化的時候需要給一個逾時時間
其儲存的不只是索引值,值是一個Entry,有額外的儲存時間欄位
在儲存的時候會加上儲存時間戳記,擷取的時候會比較一下目前時間是否逾時。逾時就清除返回null,否則就返回所需要的值。
4.2DeleteOnExitHook
File類的deleteOnExit()方法就是使用了這個類。實際上開源架構dubbo的停機也使用了其中的機制。Java目前在JVM關閉的時候提供了一個鉤子(hook),這個允許你在JVM關閉的時候執行一些代碼,這個類就是在關閉的時候執行刪除需要刪除的檔案。一般是通過Runtime.getRuntime().addShutdownHook(new Thread())進行的。DeleteOnExitHook是使用了一個sun.misc.SharedSecrets類來完成的,原理應該一樣的。hook在以下情況會生效:
1.程式運行完成退出
2.使用System.exit()方法退出
3.終端運行時使用ctrl+c中止程式
4.系統關閉
5.OutOfMemory造成宕機
6.kill pid命令殺死進程(kill -9 pid不行)
Java之IO(五)檔案系統