Guava 使用術(shù)語”流” 來表示可關(guān)閉的,并且在底層資源中有位置狀態(tài)的 I/O 數(shù)據(jù)流。術(shù)語”字節(jié)流”指的是 InputStream 或 OutputStream,”字符流”指的是 Reader 或 Writer(雖然他們的接口 Readable 和 Appendable 被更多地用于方法參數(shù))。相應(yīng)的工具方法分別在 ByteStreams 和 CharStreams 中。
大多數(shù) Guava 流工具一次處理一個(gè)完整的流,并且/或者為了效率自己處理緩沖。還要注意到,接受流為參數(shù)的 Guava 方法不會(huì)關(guān)閉這個(gè)流:關(guān)閉流的職責(zé)通常屬于打開流的代碼塊。
其中的一些工具方法列舉如下:
關(guān)于 InputSupplier 和 OutputSupplier 要注意:
在 ByteStreams、CharStreams 以及 com.google.common.io 包中的一些其他類中,某些方法仍然在使用 InputSupplier 和 OutputSupplier 接口。這兩個(gè)借口和相關(guān)的方法是不推薦使用的:它們已經(jīng)被下面描述的 source 和 sink 類型取代了,并且最終會(huì)被移除。
通常我們都會(huì)創(chuàng)建 I/O 工具方法,這樣可以避免在做基礎(chǔ)運(yùn)算時(shí)總是直接和流打交道。例如,Guava 有 Files.toByteArray(File) 和 Files.write(File, byte[])。然而,流工具方法的創(chuàng)建經(jīng)常最終導(dǎo)致散落各處的相似方法,每個(gè)方法讀取不同類型的源
或?qū)懭氩煌愋偷膮R[sink]。例如,Guava 中的 Resources.toByteArray(URL)和 Files.toByteArray(File)做了同樣的事情,只不過數(shù)據(jù)源一個(gè)是 URL,一個(gè)是文件。
為了解決這個(gè)問題,Guava 有一系列關(guān)于源與匯的抽象。源或匯指某個(gè)你知道如何從中打開流的資源,比如 File 或 URL。源是可讀的,匯是可寫的。此外,源與匯按照字節(jié)和字符劃分類型。
字節(jié) | 字符 | |
讀 | ByteSource | CharSource |
寫 | ByteSink | CharSink |
源與匯 API 的好處是它們提供了通用的一組操作。比如,一旦你把數(shù)據(jù)源包裝成了 ByteSource,無論它原先的類型是什么,你都得到了一組按字節(jié)操作的方法。
Guava 提供了若干源與匯的實(shí)現(xiàn):
此外,你也可以繼承這些類,以創(chuàng)建新的實(shí)現(xiàn)。
注:把已經(jīng)打開的流(比如 InputStream)包裝為源或匯聽起來是很有誘惑力的,但是應(yīng)該避免這樣做。源與匯的實(shí)現(xiàn)應(yīng)該在每次 openStream()方法被調(diào)用時(shí)都創(chuàng)建一個(gè)新的流。始終創(chuàng)建新的流可以讓源或匯管理流的整個(gè)生命周期,并且讓多次調(diào)用 openStream()返回的流都是可用的。此外,如果你在創(chuàng)建源或匯之前創(chuàng)建了流,你不得不在異常的時(shí)候自己保證關(guān)閉流,這壓根就違背了發(fā)揮源與匯 API 優(yōu)點(diǎn)的初衷。
一旦有了源與匯的實(shí)例,就可以進(jìn)行若干讀寫操作。
所有源與匯都有一些方法用于打開新的流用于讀或?qū)?。默認(rèn)情況下,其他源與匯操作都是先用這些方法打開流,然后做一些讀或?qū)?,最后保證流被正確地關(guān)閉了。這些方法列舉如下:
//Read the lines of a UTF-8 text file
ImmutableList<String> lines = Files.asCharSource(file, Charsets.UTF_8).readLines();
//Count distinct word occurrences in a file
Multiset<String> wordOccurrences = HashMultiset.create(
Splitter.on(CharMatcher.WHITESPACE)
.trimResults()
.omitEmptyStrings()
.split(Files.asCharSource(file, Charsets.UTF_8).read()));
//SHA-1 a file
HashCode hash = Files.asByteSource(file).hash(Hashing.sha1());
//Copy the data from a URL to a file
Resources.asByteSource(url).copyTo(Files.asByteSink(file));
除了創(chuàng)建文件源和文件的方法,F(xiàn)iles 類還包含了若干你可能感興趣的便利方法。
createParentDirs(File) | 必要時(shí)為文件創(chuàng)建父目錄 |
getFileExtension(String) | 返回給定路徑所表示文件的擴(kuò)展名 |
getNameWithoutExtension(String) | 返回去除了擴(kuò)展名的文件名 |
simplifyPath(String) | 規(guī)范文件路徑,并不總是與文件系統(tǒng)一致,請(qǐng)仔細(xì)測試 |
fileTreeTraverser() | 返回 TreeTraverser 用于遍歷文件樹 |