File類
文件和目錄路徑名的抽象表示形式。
我們知道,對於不同的操作系統,文件路徑的描述是不同的
比如
windows平台:用\
linux平台:用/
File是Java為了這一概念提供的抽象描述,與系統無關的視圖
抽象路徑名
有兩個組件:
1.可選的與系統有關的前綴 字符串 比如盤符,"/" 表示 UNIX 中的根目錄,"\\\\" 表示 Microsoft Windows UNC 路徑名
2.零個或者多個 字符串 名稱 序列
第一個名稱是 目錄名,第一個名稱之后每個名稱表示一個目錄,最后一個名稱既可以是目錄,也可以是名稱
空 抽象路徑名沒有前綴和名稱序列
|
注意:
既然最后一個名稱可以是目錄,也可以是文件名稱,那么File 並不一定就是一個文件,也可以是一個文件路徑,也就是目錄
構造方法
java中使用File來抽象表示 文件/目錄這一個概念
也就是在Java中,想要表示一個文件,構造一個File對象即可
構造方法
File(File parent, String child) 根據 parent 抽象路徑名和 child 路徑名字符串創建一個新 File 實例。 |
File(String pathname) 通過將給定路徑名字符串轉換為抽象路徑名來創建一個新 File 實例。 |
File(String parent, String child) 根據 parent 路徑名字符串和 child 路徑名字符串創建一個新 File 實例。 |
File(URI uri) 通過將給定的 file: URI 轉換為一個抽象路徑名來創建一個新的 File 實例。 |
通過路徑構造一個File,是最自然地做法
File(File parent, String child)根據參數file的路徑和child字符串進行組合
File(String parent, String child)根據參數 parent字符串和child字符串組合
本質上也就還是路徑,不過很顯然,拼接 child 就可以進行創建子目錄
URI是統一資源標識符,將文件轉換成一個鏈接,可以網絡訪問 ,通過這個URI 也可以用來生成文件
new File只是在java中描述這么一個文件,是否真的存在? 你還需要進行去驗證,只是一個虛擬的描述符
File file = new File("D:\\testFile");//file就是對這個路徑的一個描述,那么是否真的存在? 你還需要進行去驗證 |
名稱與路徑的分隔符
另外File 中還包括兩個分隔符
目錄分隔符 名稱分隔符的兩種形式 char 和 String
separatorChar public static final char separatorChar |
與系統有關的默認名稱分隔符。
此字段被初始化為包含系統屬性 file.separator 值的第一個字符。
在 UNIX 系統上,此字段的值為 '/';在 Microsoft Windows 系統上,它為 '\\'。
|
separator public static final String separator |
與系統有關的默認名稱分隔符,為了方便,它被表示為一個字符串。此字符串只包含一個字符,即 separatorChar。 |
pathSeparatorChar public static final char pathSeparatorChar |
與系統有關的路徑分隔符。 此字段被初始為包含系統屬性 path.separator 值的第一個字符。 此字符用於分隔以路徑列表 形式給定的文件序列中的文件名。 在 UNIX 系統上,此字段為 ':';在 Microsoft Windows 系統上,它為 ';'。 |
pathSeparator public static final String pathSeparator |
與系統有關的路徑分隔符,為了方便,它被表示為一個字符串。
此字符串只包含一個字符,即 pathSeparatorChar。
|
File API分類
File既可能是目錄,也可能是文件
那么,他必然提供了文件和目錄的一些基本常見操作
按照文件的屬性以及相關操作對API進行分類
文件自身屬性讀取 |
getName()
getParent()
getParentFile()
getPath()
isHidden()
lastModified()
length()
isAbsolute()
isDirectory()
isFile()
exists()
getAbsoluteFile()
getAbsolutePath()
getCanonicalFile()
getCanonicalPath()
getFreeSpace()
getTotalSpace()
getUsableSpace()
|
創建文件/目錄基本操作
|
mkdir()
mkdirs()
delete()
deleteOnExit()
renameTo(File)
createTempFile(String, String)
createTempFile(String, String, File)
createNewFile()
|
文件/目錄 列表讀取 |
listRoots()
list()
list(FilenameFilter)
listFiles()
listFiles(FileFilter)
listFiles(FilenameFilter)
|
文件權限訪問以及文件信息設置 |
canExecute()
canRead()
canWrite()
setExecutable(boolean)
setExecutable(boolean, boolean)
setReadable(boolean)
setReadable(boolean, boolean)
setReadOnly()
setWritable(boolean)
setWritable(boolean, boolean)
setLastModified(long)
|
其他 |
toPath()
toString()
toURI()
equals(Object)
compareTo(File)
hashCode()
|
File API詳解
測試:
File相關的基礎信息屬性
public String getName() | 返回由此抽象路徑名表示的文件或目錄的名稱。 該名稱是路徑名名稱序列中的最后一個名稱。如果路徑名名稱序列為空,則返回空字符串。 測試信息: getName(): cccc.txt |
public String getParent() | 返回此抽象路徑名父目錄的路徑名字符串; 如果此路徑名沒有指定父目錄,則返回 null。 getParent(): D:\testFile |
public File getParentFile() | public String getParent() 的File形式,等同於new File(getParent()) |
public String getPath() | 將此抽象路徑名轉換為一個路徑名字符串。 所得字符串使用 默認名稱分隔符 分隔名稱序列中的名稱。 |
一個File用於描述一個抽象路徑名
這個抽象路徑名(File) 的名稱 name為 路徑名名稱序列中的最后一個名稱
public boolean isHidden() | 是否隱藏文件 測試此抽象路徑名指定的文件是否是一個隱藏文件。 隱藏 的具體定義與系統有關 |
public long lastModified()
|
long 毫秒數 表示文件最后一次被修改的時間的 long 值, 用與時間點(1970 年 1 月 1 日,00:00:00 GMT)之間的毫秒數表示; 如果該文件不存在,或者發生 I/O 錯誤,則返回 0L |
public long length() | 長度,字節 返回由此抽象路徑名表示的文件的長度。 如果此路徑名表示一個目錄,則返回值是不確定的。
此抽象路徑名表示的文件的長度,以字節為單位;
如果文件不存在,則返回 0L。
對於表示特定於系統的實體(比如設備或管道)的路徑名,某些操作系統可能返回 0L。
|
public boolean isAbsolute() |
是否絕對路徑
測試此抽象路徑名是否為絕對路徑名。絕對路徑名的定義與系統有關。
在 UNIX 系統上,如果路徑名的前綴是 "/",那么該路徑名是絕對路徑名。
在 Microsoft Windows 系統上,
如果路徑名的前綴是后跟 "\\" 的盤符,或者是 "\\\\",那么該路徑名是絕對路徑名。
|
public boolean isDirectory() | 當且僅當此抽象路徑名表示的文件存在且 是一個目錄時,返回 true;否則返回 false |
public boolean isFile() | 當且僅當此抽象路徑名表示的文件存在且 是一個標准文件時,返回 true;否則返回 false |
public boolean exists() | 當且僅當此抽象路徑名表示的文件或目錄存在時,返回 true;否則返回 false |
public String getAbsolutePath() | 絕對路徑名字符串,它與此抽象路徑名表示相同的文件或目錄 |
public File getAbsoluteFile()
|
絕對 抽象路徑名,它與此抽象路徑名表示相同的文件或目錄 相當於new File(this.getAbsolutePath())
|
規范路徑名是絕對路徑名,並且是惟一的。規范路徑名的准確定義與系統有關。
如有必要,此方法首先將路徑名轉換為絕對路徑名,這與調用 getAbsolutePath() 方法的效果一樣,然后用與系統相關的方式將它映射到其惟一路徑名。
這通常涉及到從路徑名中移除多余的名稱(比如 "." 和 "..")、解析符號連接(對於 UNIX 平台),以及將驅動器號轉換為標准大小寫形式(對於 Microsoft Windows 平台)。
每個表示現存文件或目錄的路徑名都有一個惟一的規范形式。
每個表示不存在文件或目錄的路徑名也有一個惟一的規范形式。
不存在文件或目錄路徑名的規范形式可能不同於創建文件或目錄之后同一路徑名的規范形式。
同樣,現存文件或目錄路徑名的規范形式可能不同於刪除文件或目錄之后同一路徑名的規范形式。
public String getCanonicalPath()
throws IOException
|
規范路徑名字符串,它與此抽象路徑名表示相同的文件或目錄
|
public File getCanonicalFile()
throws IOException
|
等同於 new File(this.getCanonicalPath()) |
public long getFreeSpace()
public long getTotalSpace()
public long getUsableSpace()
|
返回此抽象路徑名指定的分區中空間相關的數據信息,一定注意是抽象路徑名指定的分區 未分配 /全部/已使用 空間情況 單位是字節數 |
File相關的操作
創建 重命名 刪除等
mkdir()
|
創建此抽象路徑名指定的目錄,當且僅當已創建目錄時,返回 true;否則返回 false |
mkdirs() | 創建此抽象路徑名指定的目錄,包括所有必需但不存在的父目錄。 注意,此操作失敗時也可能已經成功地創建了一部分必需的父目錄。 |
mkdir/mkdirs 用於創建目錄
mkdir只會創建最后一個名稱為名稱的目錄, 如果一個路徑的parent不存在,並不會創建成功
mkdirs 則會創建所有
public boolean renameTo(File dest) | 重新命名此抽象路徑名表示的文件。 參數為File
此方法行為的許多方面都是與平台有關的:重命名操作無法將一個文件從一個文件系統移動到另一個文件系統,
該操作不是不可分的,如果已經存在具有目標抽象路徑名的文件,那么該操作可能無法獲得成功。
應該始終檢查返回值,以確保重命名操作成功。
|
他的參數為File 也是一個抽象路徑名 所以說不僅僅就是改一下文件的最后一個名稱
他可以把文件進行移動
public boolean delete() | 刪除此抽象路徑名表示的文件或目錄。如果此路徑名表示一個目錄,則該目錄必須為空才能刪除。
當且僅當成功刪除文件或目錄時,返回 true;否則返回 false
|
public void deleteOnExit() |
在虛擬機終止時,請求刪除此抽象路徑名表示的文件或目錄。
文件(或目錄)將以與注冊相反的順序刪除。
調用此方法刪除已注冊為刪除的文件或目錄無效。
根據 Java 語言規范中的定義,只有在虛擬機正常終止時,才會嘗試執行刪除操作。
一旦請求了刪除操作,就無法取消該請求。所以應小心使用此方法。
|
file1 是文件 file2是目錄,但是目錄下還有文件
所以file1刪除成功 file2刪除失敗
public static File createTempFile(String prefix,
String suffix,
File directory)
throws IOException
|
在指定目錄中創建一個新的空文件,使用給定的前綴和后綴字符串生成其名稱。 如果 directory 參數為 null,則使用與系統有關的默認臨時文件目錄 默認臨時文件目錄由系統屬性 java.io.tmpdir 指定 |
public static File createTempFile(String prefix,
String suffix)
throws IOException
|
在默認臨時文件目錄中創建一個空文件,使用給定前綴和后綴生成其名稱。 調用此方法等同於調用 createTempFile(prefix, suffix, null) |
public boolean createNewFile()
throws IOException
|
當且僅當不存在具有此抽象路徑名指定名稱的文件時,不可分地創建一個新的空文件。 檢查文件是否存在,若不存在則創建該文件 如果指定的文件不存在並成功地創建,則返回 true;如果指定的文件已經存在,則返回 false |
File相關的列表查詢
public String[] list() | 返回一個字符串數組,這些字符串指定此抽象路徑名表示的目錄中的文件和目錄。
如果此抽象路徑名不表示一個目錄,那么此方法將返回 null。
否則返回一個字符串數組,每個數組元素對應目錄中的每個文件或目錄。
表示目錄本身及其父目錄的名稱不包括在結果中。每個字符串是一個文件名,而不是一條完整路徑。
|
public String[] list(FilenameFilter filter) | 返回一個字符串數組,這些字符串指定此抽象路徑名表示的目錄中滿足指定過濾器的文件和目錄。 除了返回數組中的字符串必須滿足過濾器外,此方法的行為與 list() 方法相同。 如果給定 filter 為 null,則接受所有名稱。 |
public File[] listFiles() | 返回一個抽象路徑名數組,這些路徑名表示此抽象路徑名表示的目錄中的文件。 如果此抽象路徑名不表示一個目錄,那么此方法將返回 null。 否則返回一個 File 對象數組,每個數組元素對應目錄中的每個文件或目錄。 表示目錄本身及其父目錄的名稱不包括在結果中。 不保證所得數組中的相同字符串將以特定順序出現,特別是不保證它們按字母順序出現。 |
public File[] listFiles(FilenameFilter filter) | 除了返回數組中的路徑名必須滿足過濾器外,此方法的行為與 listFiles() 方法相同 如果給定 filter 為 null,則接受所有路徑名 |
public File[] listFiles(FileFilter filter) | 除了返回數組中的路徑名必須滿足過濾器外,此方法的行為與 listFiles() 方法相同。 如果給定 filter 為 null,則接受所有路徑名。 |
public static File[] listRoots() |
列出可用的文件系統根。
特定 Java 平台可以支持零個或更多個分層組織的文件系統。
每個文件系統有一個 root 目錄,可以從這里到達文件系統中的所有其他文件。
例如,Windows 平台為每個活動驅動器提供了一個根目錄;
UNIX 平台只有一個根目錄,即 "/"。
可用文件系統根的設置受各種系統級操作的影響,比如可移動介質的插入和彈出,以及斷開或卸載那些物理磁盤或虛擬磁盤。
此方法返回一個 File 對象數組,這些對象表示可用文件系統根的根目錄。
可以保證本地機器上物理存在的任何文件的規范路徑名都以此方法返回的根之一開始。
|
list返回的是名稱列表 ,必須是一個目錄
listFile返回的是File列表 必須是一個目錄
ps:直接打印f 調用的是toString 形式,返回的是path
過濾器形式的與無參數版本的行為是相同的,只不過是還要符合過濾器的要求
對於FilenameFilter 和 FileFilter,他們是函數式接口
可以直接使用lambda表達式傳入參數
File相關權限設置
public boolean canExecute() | 測試應用程序是否可以執行此抽象路徑名表示的文件。 |
public boolean canRead() | 測試應用程序是否可以讀取此抽象路徑名表示的文件。 |
public boolean canRead() | 測試應用程序是否可以修改此抽象路徑名表示的文件。 |
setExecutable(boolean)
setExecutable(boolean, boolean)
|
設置此抽象路徑名的所有者或所有用戶的執行權限。
executable - 如果為 true,則設置允許執行操作的訪問權限;如果為 false,則不允許執行操作。
ownerOnly - 如果為 true,則執行權限只適用於所有者的執行權限;否則適用於所有用戶。
如果底層文件系統不能區分所有者執行權限與其他執行權限,那么無論該參數為何值,執行權限將適用於所有用戶。
單參數版本是雙參數版本的快捷默認設置形式
file.setExcutable(arg) 形式的調用與以下調用的行為完全相同:file.setExecutable(arg, true)
也就是單參數默認是設置當前用戶
|
setReadable(boolean)
setReadable(boolean, boolean)
|
設置此抽象路徑名的所有者或所有用戶的讀權限。 其余的用法形式同setExecutable |
setWritable(boolean)
setWritable(boolean, boolean)
|
設置此抽象路徑名的所有者或所有用戶的寫權限。
其余的用法形式同setExecutable
|
setExecutable/setReadable/setWritable 用於設置 執行 讀 寫 權限
雙參數版本 第一個參數表示是否允許,第二個參數表示是否是用於所有的用戶
一個參數版本是兩個參數版本的當前用戶的簡化快捷形式
public boolean setReadOnly() |
標記此抽象路徑名指定的文件或目錄,從而只能對其進行讀操作。
調用此方法后,可以保證在被刪除或被標記為允許寫訪問之前,文件或目錄不會發生更改。
是否可以刪除某個只讀文件或目錄則取決於底層系統。
|
public boolean setLastModified(long time) | 設置此抽象路徑名指定的文件或目錄的最后一次修改時間。 |
其他
public Path toPath() | 返回一個java.nio.file.Path 從這個抽象路徑構造的Path對象 1.7新增的 |
public String toString() | 返回此抽象路徑名的路徑名字符串。該字符串就是 getPath() 方法返回的字符串。
public String toString() {
return getPath();
}
|
public URI toURI() |
構造一個表示此抽象路徑名的 file: URI。
該 URI 的具體形式與系統有關。如果可以確定此抽象路徑名表示的文件是一個目錄,那么所得 URI 將以斜杠結束。
對於某個給定抽象路徑名 f,可保證:
new File( f.toURI()).equals( f.getAbsoluteFile())
|
public int compareTo(File pathname) | 按字母順序比較兩個抽象路徑名。此方法定義的順序取決於底層系統。 在 UNIX 系統上,比較路徑名時,字母大小寫通常很重要,而在 Microsoft Windows 系統上,這通常不重要。 依賴 |
public boolean equals(Object obj) | 測試此抽象路徑名與給定對象是否相等。 當且僅當該參數不是 null,而是一個與此抽象路徑名表示相同的文件或目錄的抽象路徑名時,返回 true。 兩個抽象路徑名是否相等取決於底層系統。 在 UNIX 系統上,比較路徑名時,字母大小寫通常很重要,而在 Microsoft Windows 系統上,這通常不重要。 |
public int hashCode() | 計算此抽象路徑名的哈希碼。 因為抽象路徑名的相等性與系統有關,所以對其哈希碼的計算也與系統有關。 在 UNIX 系統上,抽象路徑名的哈希碼等於其路徑名字符串和十進制值 1234321 的哈希碼的異或。 在 Microsoft Windows 系統上,哈希碼等於其轉換為小寫的路徑名字符串和十進制值 1234321 的哈希碼的異或。 在將路徑名字符串轉換為小寫時不考慮語言環境。 |
FileSystem簡介
File中有一個變量fs 類型為FileSystem
compareTo方法依賴於他
而equals方法又依賴compareTo
hashCode也是依賴他
所以說:
compareTo equals hashCode 都依賴於 FileSystem fs
其實你在回頭看看整個File文件中,很多個地方都出現了fs的身影
FileSystem到底是什么?
操作系統有各自的文件系統,這些文件系統又存在很多差異,而Java 因為是跨平台的,所以它必須要統一處理這些不同平台文件系統之間的差異,才能往上提供統一的入口。
說白了又是接口來實現統一,不同的操作系統實現這個接口,就可以提供統一的表現形式
FileSystem是一個抽象類
windows下的實現類為:WinNTFileSystem,在IDE中可以直接找到
可能你只是找到了一個WinNTFileSystem,只有一個要接口還有什么意思?
如果你目前只看到了一個WinNTFileSystem 那說明你在Windows下
WinNTFileSystem類 和 UnixFileSystem類並不是在同一個 JDK 里面,也就是說它們是分開的
你只能在 Windows 版本的 JDK 中找到 WinNTFileSystem,而在 Linux 版本的 JDK 中找到 UnixFileSystem
同樣地,其他操作系統也有自己的文件系統實現類。
接下來大致的看下WinNTFileSystem
屬性
private final char slash;//斜杠符號 private final char altSlash;//與slash相反的斜杠 private final char semicolon;//分號 private static String[] driveDirCache = new String[26];//表示驅動盤目錄緩存 private ExpiringCache cache = new ExpiringCache();//用於緩存標准路徑 private ExpiringCache prefixCache = new ExpiringCache();//用於緩存標准路徑前綴
其實slash就是名稱分隔符
semicolon就是路徑分隔符
構造方法中根據系統變量對文件分隔符和路徑分隔符進行初始化
isSlash 和 isLetter都非常簡單,簡單的判斷
判斷是否以slash 開頭,是的話直接返回,不是的話,給他加一個
getSeparator 和 getPathSeparator 就是File中分隔符的來處
路徑的標准化
不光標准化,前面還提到了規范化路徑 File中有方法getCanonicalFile getCanonicalPath
他們到底都是在說什么事情呢
先說下標准化,看一個例子
雖然看起來很奇怪,但是不影響程序運行
我們此時可以用比較通俗的話來描述這個情況
我們給出來了一個亂七八糟的路徑,最終路徑按照當前文件系統的規則,進行了解析,
去除了不必要的分隔符 或者可能把錯誤的分隔符進行替換等按照一定的規則
整理出來一個合理的路徑,這就是標准化
|
debug 看下File的構造方法 就知道了
最終他幫我們正確的解析了路徑,這就是標准化
可以看得出來,標准化,借助的仍舊是fs 也就是FileSystem
在WinNTFileSystem 中的normalize方法就是標准化路徑的一個對外接口
他還有兩個相關的private方法,用於處理細節
方法的具體過程,到底是怎么處理的,有興趣的同學可以繼續深挖以下
仔細看下注釋也可理解一二
一個標准的win32路徑名,不能包括重復的名稱分隔符(斜杠) UNC除外 ,也不能以名稱分隔符(斜杠)結束
可能是一個空的String
規范化Win32路徑名具有便捷的特點:前綴的長度幾乎唯一地標識了路徑的類型
無論它是絕對的還是相對的
0,1,2,3是分類說明
如同上面標准化描述的一樣,前綴的長度對於標准化很有用,這個方法經常被使用
還是剛才的文件夾列表 這次使用另外的構造方法
File file = new File("D:\\\\\\/testFile///////\\\\","\\///wdwqdwqwd.java"); if (file.exists()){ System.out.println(file.getName()); }
所以可以看得出來resolve做的事情
他要求傳遞進去的兩個字符串都是normal的,所以入參傳遞進去時,就做了處理
雖然說兩個都是normal但是兩個拼接起來的情況還是很可能需要處理的,
比如子路徑如果以 slash 開頭,丟棄它的頭部,所以子路徑從第2的位置開始
雙參數的resolve就是解決這個問題的
一個參數的resolve
public String resolve(File f)
也是類似的道理
只不過他處理的是一個File
|
規范化路徑
此處的規范化的含義與File中介紹的返回規范化路徑和文件是一致的
看下File中的調用即可,依賴的就是這個方法
resolve normal canonicalize方法本質是一樣的,此處說的本質指的是邏輯切入點
他們都是為了處理路徑的,只不過是基於不同的場景下去解析組織返回路徑
normal最單純
resolve 用於合並路徑,或者將一個File轉換為路徑
canonicalize 是一個絕對路徑,並且是唯一的形式
WinNTFileSystem 還有不少方法,其中有些還是本地方法,只需要大致了解功能即可
不是public的外面也用不了
不過這個類對於了解File 的基本實現是很有幫助的
因為可以說File非常非常的依賴他
UnixFileSystem的邏輯概念也是類似的,算是廢話了,畢竟都是實現同一個接口
本文主要對java中 抽象路徑名 File這一概念進行了詳細的解讀
並且介紹了File 依賴的底層接口 FileSystem 文件系統
不同的操作系統有不同的文件系統,FileSystem 接口用於提供一致性的操作訪問
不同的操作系統提供不同的實現類
操作文件依賴底層操作系統,所以File 也必然依賴底層系統
關於文件系統中的規范化標准化可能會有一定的疑惑,因為
其實你跳出來代碼的思維來看,就是說window平台對於文件路徑名稱格式本身就有一些的要求
所謂標准化就是適配這種格式,就好像學生時代讓穿校服一樣,那你到了這個學校就換上這個學校的校服,沒什么好奇怪的
你給出來的一個路徑,想要在某個環境下運行,這個路徑必須是跟本地系統適配的
關於路徑相關的一些補充
根據上面的介紹,很顯然,名稱分隔符和路徑分隔符,不同平台下是不同的
File中的分隔符都是獲取的本地系統的
所以不要在你的代碼中寫死某種分隔符,而是使用File給我們提供的哪幾個public static final定義的分隔符
下面說下windows下的一些路徑概念
linux的絕對路徑是指從根目錄說起的. 例如 /home/somedir/..
而相對路徑則是從當前目錄說起: 即 ./
|
有4個相對路徑的表示方法:
當前目錄 .
父目錄 ..
某用戶的根目錄 ~user
自己的根目錄 ~
|