1. 程式人生 > >[Google Guava] 9-I/O

[Google Guava] 9-I/O

原文連結 譯文連結 譯者:沈義揚

位元組流和字元流

Guava使用術語”流” 來表示可關閉的,並且在底層資源中有位置狀態的I/O資料流。術語”位元組流”指的是InputStream或OutputStream,”字元流”指的是Reader 或Writer(雖然他們的介面Readable 和Appendable被更多地用於方法引數)。相應的工具方法分別在ByteStreamsCharStreams中。

大多數Guava流工具一次處理一個完整的流,並且/或者為了效率自己處理緩衝。還要注意到,接受流為引數的Guava方法不會關閉這個流:關閉流的職責通常屬於開啟流的程式碼塊。

其中的一些工具方法列舉如下:

關於InputSupplier 和OutputSupplier要注意:

在ByteStreams、CharStreams以及com.google.common.io包中的一些其他類中,某些方法仍然在使用InputSupplier和OutputSupplier介面。這兩個藉口和相關的方法是不推薦使用的:它們已經被下面描述的source和sink型別取代了,並且最終會被移除。

源與匯

通常我們都會建立I/O工具方法,這樣可以避免在做基礎運算時總是直接和流打交道。例如,Guava有Files.toByteArray(File) 和Files.write(File, byte[])。然而,流工具方法的建立經常最終導致散落各處的相似方法,每個方法讀取不同型別的源

或寫入不同型別的匯[sink]。例如,Guava中的Resources.toByteArray(URL)和Files.toByteArray(File)做了同樣的事情,只不過資料來源一個是URL,一個是檔案。

為了解決這個問題,Guava有一系列關於源與匯的抽象。源或匯指某個你知道如何從中開啟流的資源,比如File或URL。源是可讀的,匯是可寫的。此外,源與匯按照位元組和字元劃分型別。

源與匯API的好處是它們提供了通用的一組操作。比如,一旦你把資料來源包裝成了ByteSource,無論它原先的型別是什麼,你都得到了一組按位元組操作的方法。

建立源與匯

Guava提供了若干源與匯的實現:

此外,你也可以繼承這些類,以建立新的實現。

注:把已經開啟的流(比如InputStream)包裝為源或匯聽起來是很有誘惑力的,但是應該避免這樣做。源與匯的實現應該在每次openStream()方法被呼叫時都建立一個新的流。始終建立新的流可以讓源或匯管理流的整個生命週期,並且讓多次呼叫openStream()返回的流都是可用的。此外,如果你在建立源或匯之前建立了流,你不得不在異常的時候自己保證關閉流,這壓根就違背了發揮源與匯API優點的初衷。

使用源與匯

一旦有了源與匯的例項,就可以進行若干讀寫操作。

通用操作

所有源與匯都有一些方法用於開啟新的流用於讀或寫。預設情況下,其他源與匯操作都是先用這些方法開啟流,然後做一些讀或寫,最後保證流被正確地關閉了。這些方法列舉如下:

  • openStream():根據源與匯的型別,返回InputStream、OutputStream、Reader或者Writer。
  • openBufferedStream():根據源與匯的型別,返回InputStream、OutputStream、BufferedReader或者BufferedWriter。返回的流保證在必要情況下做了緩衝。例如,從位元組陣列讀資料的源就沒有必要再在記憶體中作緩衝,這就是為什麼該方法針對位元組源不返回BufferedInputStream。字元源屬於例外情況,它一定返回BufferedReader,因為BufferedReader中才有readLine()方法。

源操作

匯操作

範例

//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));

檔案操作

除了建立檔案源和檔案的方法,Files類還包含了若干你可能感興趣的便利方法。