一、字节流和字符流
Guava 使用术语”流” 来表示可关闭的,并且在底层资源中有位置状态的I/O数据流。
字节流指的是
InputStream
或OutputStream
,字符流指的是
Reader
或Writer
(虽然他们的接口Readable
和Appendable
被更多地用于方法参数)。相应的工具方法分别在ByteStreams
和CharStreams
中。
大多数 Guava 流工具一次处理一个完整的流,并且/或者为了效率自己处理缓冲。还要注意到,接受流为参数的Guava方法不会关闭这个流:关闭流的职责通常属于打开流的代码块。
其中的一些工具方法列举如下:
ByteStreams | CharStreams |
---|---|
byte[] toByteArray(InputStream) | String toString(Readable) |
N/A | List<String> readLines(Readable) |
long copy(InputStream, OutputStream) | long copy(Readable, Appendable) |
void readFully(InputStream, byte[]) | N/A |
void skipFully(InputStream, long) | void skipFully(Reader, long) |
OutputStream nullOutputStream() | Writer nullWriter() |
二、源与汇
通常我们都会创建I/O工具方法,这样可以避免在做基础运算时总是直接和流打交道。例如:Guava有 Files.toByteArray(File)
和 Files.write(File, byte[])
。
然而,流工具方法的创建经常最终导致散落各处的相似方法,每个方法读取不同类型的源或写入不同类型的汇[sink]。例如:Guava中的 Resources.toByteArray(URL)
和 Files.toByteArray(File)
做了同样的事情,只不过数据源一个是URL,一个是文件。
为了解决这个问题,Guava有一系列关于源与汇的抽象。源或汇指某个你知道如何从中打开流的资源,比如 File
或 URL
。源是可读的,汇是可写的。此外,源与汇按照字节和字符划分类型。
操作 | 字节 | 字符 |
---|---|---|
读 | ByteSource | CharSource |
写 | ByteSink | CharSink |
源与汇API的好处是它们提供了通用的一组操作。比如,一旦你把数据源包装成了 ByteSource
,无论它原先的类型是什么,你都得到了一组按字节操作的方法。
1、创建源与汇
Guava 提供了若干源与汇的实现:
字节 | 字符 |
---|---|
Files.asByteSource(File) | Files.asCharSource(File, Charset) |
Files.asByteSink(File, FileWriteMode...) | Files.asCharSink(File, Charset, FileWriteMode...) |
Resources.asByteSource(URL) | Resources.asCharSource(URL, Charset) |
ByteSource.wrap(byte[]) | CharSource.wrap(CharSequence) |
ByteSource.concat(ByteSource...) | CharSource.concat(CharSource...) |
ByteSource.slice(long, long) | N/A |
N/A | ByteSource.asCharSource(Charset) |
N/A | ByteSink.asCharSink(Charset) |
此外,你也可以继承这些类,以创建新的实现。
注:把已经打开的流(比如InputStream
)包装为源或汇听起来是很有诱惑力的,但是应该避免这样做。源与汇的实现应该在每次 openStream()
方法被调用时都创建一个新的流。始终创建新的流可以让源或汇管理流的整个生命周期,并且让多次调用 openStream()
返回的流都是可用的。此外,如果你在创建源或汇之前创建了流,你不得不在异常的时候自己保证关闭流,这压根就违背了发挥源与汇API优点的初衷。
2、使用源与汇
一旦有了源与汇的实例,就可以进行若干读写操作。
(1)通用操作
所有源与汇都有一些方法用于打开新的流用于读或写。默认情况下,其他源与汇操作都是先用这些方法打开流,然后做一些读或写,最后保证流被正确地关闭了。这些方法列举如下:
openStream()
:根据源与汇的类型,返回InputStream
、OutputStream
、Reader
或者Writer
。openBufferedStream()
:根据源与汇的类型,返回InputStream
、OutputStream
、BufferedReader
或者BufferedWriter
,返回的流保证在必要情况下做了缓冲。
(2)源操作
字节源 | 字符源 |
---|---|
byte[] read() | String read() |
N/A | ImmutableList<String> readLines() |
N/A | String readFirstLine() |
long copyTo(ByteSink) | long copyTo(CharSink) |
long copyTo(OutputStream) | long copyTo(Appendable) |
long size() (in bytes) | N/A |
boolean isEmpty() | boolean isEmpty() |
boolean contentEquals(ByteSource) | N/A |
HashCode hash(HashFunction) | N/A |
(3)汇操作
字节汇 | 字符汇 |
---|---|
void write(byte[]) | void write(CharSequence) |
long writeFrom(InputStream) | long writeFrom(Readable) |
N/A | void writeLines(Iterable<? extends CharSequence>) |
N/A | void writeLines(Iterable<? extends CharSequence>, String) |
3、范例
//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类还包含了若干你可能感兴趣的便利方法。
方法名 | 说明 |
---|---|
createParentDirs(File) | 必要时为文件创建父目录 |
getFileExtension(String) | 返回给定路径所表示文件的扩展名 |
getNameWithoutExtension(String) | 返回去除了扩展名的文件名 |
simplifyPath(String) | 规范文件路径,并不总是与文件系统一致,请仔细测试 |
fileTreeTraverser() | 返回TreeTraverser用于遍历文件树 |
四、部分示例
//guava提供了一个源与汇的概念对应读写字节字符共有4个类ByteSource,CharSource,ByteSink,CharSink URL url = new URL("this the resource url"); File file = new File("your file path"); Resources.toByteArray(url);//从url中获得字节数组 Files.toByteArray(file);//从文件中获得字节数组 CharSource charSource = Files.asCharSource(file, Charsets.UTF_8);//获得字符源 ByteSource byteSource = Files.asByteSource(file);//获得字节源 Resources.asCharSource(url, Charsets.UTF_8);//从url中获得字符源 Resources.asByteSource(url);//从url中获得字节源 CharSink charSink = Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND);//获得字符汇 以append追加方式(覆盖方式可以省略) ByteSink byteSink = Files.asByteSink(file, FileWriteMode.APPEND);//或者字节汇 以append追加方式(覆盖方式可以省略) byteSource.asCharSource(Charsets.UTF_8);//字节源转字符源 byteSink.asCharSink(Charsets.UTF_8);//字节汇转字符汇 byte[] bytes = byteSource.read();//读取出byte[] String string = charSource.read();//读取出String byteSource.copyTo(byteSink);//字节源copy到汇 可以使用OutputStream charSource.copyTo(charSink);//字符源copy到汇 可以使用Appendable byteSink.write(bytes);//写入字节 charSink.write(string);//写入字符(使用的是CharSequence,可以用String) //案例 //逐行读取 以utf-8编码 ImmutableList<String> lines = Files.asCharSource(file, Charsets.UTF_8).readLines(); //读取单词 Multiset<String> wordOccurrences = HashMultiset.create( //以空格拆分 Splitter.on(CharMatcher.whitespace()) .trimResults() .omitEmptyStrings() .split(Files.asCharSource(file, Charsets.UTF_8).read())); //获取文件按照sha1生成的hash码 HashCode hash = Files.asByteSource(file).hash(Hashing.sha1()); //File的工具类Files //将url资源copy到file中 Resources.asByteSource(url).copyTo(Files.asByteSink(file));
五、相关文章
未经允许请勿转载:程序喵 » Google Guava 快速入门 —— 文件流