IO文件操作,可以說是除了JDBC操作之外,日常最常用的功能之一了。IO的讀寫方式如何,直接影響到系統(tǒng)的性能。很多時(shí)候系統(tǒng)的性能瓶頸往往不是出現(xiàn)在對象層面,而是出現(xiàn)在底層的IO層面上。
Apache commosn IO包在input, output包的基礎(chǔ)上,提供了一個(gè)高效,方便的文件類處理工具:FileUtils,其功能涵蓋了所有日常常用的IO操作,由于這個(gè)類的部分方法底層是基于Apache commons IO自己的讀寫流去實(shí)現(xiàn)的,所以在性能上會(huì)相對高于JDK自帶的類(具體原因可以參考這篇文章:IO與文件讀寫---使用Apache commons io包提高讀寫效率)
根據(jù)Apache commons IO官方的說法,這個(gè)類可以提供如下功能:
總體上來說,主要有:
※ 資源的創(chuàng)建、刪除
※ 資源的復(fù)制、移動(dòng)
※ 資源的讀寫
※ 資源的比較
※ 資源的過濾
※ 資源的轉(zhuǎn)換
【二】FileUtils的常用API及解析
①資源的創(chuàng)建、刪除
※ 目錄的創(chuàng)建:
forceMkdir(File directory),這個(gè)方法可以在父目錄不存在的情況下,連續(xù)創(chuàng)建多個(gè)目錄。但如果同名的目錄已經(jīng)存在或者無權(quán)創(chuàng)建,則拋出異常
※ 文件的創(chuàng)建:
touch(File file),這個(gè)方法用于創(chuàng)建一個(gè)size為0的文件,然后迅速關(guān)閉輸出流。如果文件已經(jīng)存在則簡單地修改一下文件的modify time
※ 目錄/文件的刪除:
void deleteDirectory(File directory),遞歸地刪除目錄及其下的所有內(nèi)容。
boolean deleteQuietly(File file),相比于JDK的delete()方法有兩個(gè)不同:首先它不需要被刪除目錄下的內(nèi)容為空,其次它不會(huì)拋出任何IOException。
void forceDelete(File file),強(qiáng)行刪除file對象,如果是目錄對象則遞歸刪除子目錄。如果刪除失敗則顯式地拋出IOException。
void forceDeleteOnExit(File file),當(dāng)JVM退出時(shí),把file對象刪除。如果是目錄對象則遞歸刪除子目錄。
②資源的復(fù)制、移動(dòng)
※ 復(fù)制目錄或文件
copyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate),這個(gè)方法用于把源目錄及其下面的子目錄,文件一起拷貝到目標(biāo)位置(名稱可改)。而且該方法允許在拷貝的過程中進(jìn)行過濾,指定僅拷貝那些符合條件的資源。最后一個(gè)選項(xiàng)用來表明是否保留文件原有的創(chuàng)建、修改日期還是使用最新的日期。
copyDirectoryToDirectory(File srcDir, File destDir),這個(gè)方法和上面的區(qū)別在于:首先上面的方法是拷貝到destDir的位置,而這個(gè)方法是拷貝到destDir“之下”的位置。其次上面的方法可以在拷貝的同時(shí)改名,這個(gè)方法不能,拷貝后仍然使用原來的名稱。
copyFile(File srcFile, File destFile, boolean preserveFileDate),類似于上面的copyDirectory方法。
copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate),類似與上面的copyDirectoryToDirectory方法。
※ 移動(dòng)目錄或文件
moveToDirectory(File srcFile, File destDir, boolean createDestDir),這個(gè)方法用于移動(dòng)一個(gè)文件或者目錄到指定位置。
③資源的讀寫
這一部分是FileUtils的精華部分。
※ 讀入文件
FileUtils支持對文件以字節(jié)數(shù)組,字符串,行的方式讀入。對應(yīng)方法分別是:
byte[] readFileToByteArray(File file)
String readFileToString(File file)
String readFileToString(File file, String encoding)
List readLines(File file)
List readLines(File file, String encoding)
這里我們關(guān)心的是對于大文件,F(xiàn)ileUtils是如何讀入的?看看下面的源代碼:



















可以見到這個(gè)方法調(diào)用了IOUtils的toString方法,那么這個(gè)過程的底層細(xì)節(jié)是如何的呢?










































可以看到,Apache commons IO的底層是采用InputStreamReader來讀的,而且是連續(xù)不斷地在內(nèi)存中構(gòu)造String對象,如果有一個(gè)2G文件,那么將會(huì)在內(nèi)存中構(gòu)造一個(gè)2G的String對象。
※ 寫入文件
void writeLines(File file, String encoding, Collection lines, String lineEnding),這個(gè)用法用于將內(nèi)存中一個(gè)集合的內(nèi)容持久化到本地文件,以行的方式寫入每一個(gè)集合元素。可以指定編碼和換行符。
這個(gè)方法的適用場景類似于:將內(nèi)存中的一批“客戶信息集合”導(dǎo)出到文件中






























void writeStringToFile(File file, String data, String encoding),這個(gè)方法將字符串一次性寫入文件










④資源的比較
※ 文件時(shí)間比較
boolean isFileNewer(File file, Date/File/Long) 和boolean isFileOlder(File file, Date/File/Long)兩種方法,這兩種方法的內(nèi)部都是采用文件的last modify time進(jìn)行比較的。
※ 文件內(nèi)容比較
boolean contentEquals(File file1, File file2)采用逐字節(jié)比較的方式,在正式比較內(nèi)容之前,會(huì)先比較以下項(xiàng)目:存在性、類型、長度、鏈接指向,最后才是比較內(nèi)容

































⑤資源的過濾
FileUtils提供了兩種類型的方法讓使用者可以輕松地過濾文件、目錄。它們分別是:
※ 基于Iterator形式的過濾
iterateFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter),這個(gè)方法用于從指定的目錄下過濾文件。通過fileFilter我們可以指定要過濾的文件類型,通過dirFilter我們可以指定是否對子目錄進(jìn)行同樣的過濾。如果為null則子目錄不參與過濾。
iterateFiles(File directory, String[] extensions, boolean recursive),這個(gè)方法用于從指定的目錄下過濾文件。通過extensions我們可以指定要過濾的文件擴(kuò)展名,通過recurisve我們可以指定是否對子目錄進(jìn)行同樣的過濾。如果為false則子目錄不參與過濾。
※ 基于Collection形式的過濾
listFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter),這個(gè)方法和基于Iterator形式的過濾相同,只是返回的值是一個(gè)集合。
listFiles(File directory, String[] extensions, boolean recursive),這個(gè)方法和基于Iterator形式的過濾相同,只是返回的值是一個(gè)集合。
⑥資源的轉(zhuǎn)換
※ 從URL形式到File形式的轉(zhuǎn)換
File toFile(URL url),這個(gè)轉(zhuǎn)換會(huì)首先將file://這個(gè)Prefix去掉,然后使用normalize方法對路徑進(jìn)行規(guī)范。
※ 從File形式到URL形式的轉(zhuǎn)換
URL[] toURLs(File[] files),這個(gè)轉(zhuǎn)換或?qū)ξ募穆窂郊由蟜ile://這個(gè)prefix,然后對路徑進(jìn)行規(guī)范。
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。