I/O:针对Java 5和6版本的简化的I/O操作,尤其是在整个I/O流和文件上。
1.ByteStreams
和CharStreams
Guava使用术语“流”来表示在底层资源中具有位置状态I/O数据的Closeable
流。术语"字节
流"是指InputStream
或OutputStream
,而"字符
流"是指Reader
或Writer
(尽管它们的超类型Readable
和Appendable
通常用作方法参数类型)。相应的工具分为工具类ByteStreams
和CharStreams
。
大多数与Guava流相关的工具一次处理整个流[和/或]处理自身的缓冲以提高效率。还要注意,获取流的Guava方法不会关闭流:关闭流通常是打开流的代码的责任。
这些类提供的一些方法包括:
ByteStreams | CharStreams |
---|---|
byte[]toByteArray(InputStream) | StringtoString(Readable) |
N/A | List<String>readLines(Readable) |
longcopy(InputStream,OutputStream) | longcopy(Readable,Appendable) |
voidreadFully(InputStream,byte[]) | N/A |
voidskipFully(InputStream,long) | voidskipFully(Reader,long) |
OutputStreamnullOutputStream() | WriternullWriter() |
2.Sources and sinks
创建I/O工具方法很常见,该方法可以帮助你在进行基本操作时完全避免处理流。例如,Guava有Files.toByteArray(File)
和Files.write(File, byte[])
。但是,最终你将得到类似的方法,这些方法遍布各处,每种方法都处理不同类型的数据源或可写入数据的接收器。例如,Guava有Resources.toByteArray(URL)
,它与Files.toByteArray(File)
作用相同,但是使用URL
作为数据源而不是文件。
为了解决这个问题,Guava对不同类型的数据源和接收器提供了一组抽象。源或接收器是你知道如何打开新流的某种资源,例如File
或URL
。源是可读的,而接收器是可写的。此外,根据你要处理的是字节
数据还是字符
数据,还细分了源和接收器。
操作 | 字节 | 字符 |
---|---|---|
Reading | ByteSource | CharSource |
Writing | ByteSink | CharSink |
这些API的优点是它们提供了一组通用的操作。例如,一旦将数据源包装为ByteSource
后,无论该源是什么,都将获得相同的方法集。
2.1创建sources and sinks
Guava提供了许多源和接收器实现:
字节 | 字符 |
---|---|
Files.asByteSource(File) | Files.asCharSource(File,Charset) |
Files.asByteSink(File,FileWriteMode...) | Files.asCharSink(File,Charset,FileWriteMode...) |
MoreFiles.asByteSource(Path,OpenOption...) | MoreFiles.asCharSource(Path,Charset,OpenOption...) |
MoreFiles.asByteSink(Path,OpenOption...) | MoreFiles.asCharSink(Path,Charset,OpenOption...) |
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 |
CharSource.asByteSource(Charset) | ByteSource.asCharSource(Charset) |
N/A | ByteSink.asCharSink(Charset) |
此外,你可以自己扩展源和接收器类以创建新的实现。
注意 :虽然可能很想创建一个包装打开流(例如InputStream
)的源或接收器,但应避免这种情况。你的源/接收器应该在每次调用其openStream()
方法时打开一个新流。这允许源或接收器控制该流的整个生命周期,并使其可以多次使用,而不是第一次调用该流上的任何方法而变得不可用。此外,如果你在创建源或接收器之前打开流,那么如果在代码的其他地方抛出异常,则可能还必须确保正确关闭流,这会破坏首先使用源或接收器的许多优点。
2.2使用Sources and Sinks
一旦有了源或接收器实例,就可以访问许多用于读取或写入的操作。
2.2.1通用操作
所有源和接收器都提供了打开新流以进行读取或写入的功能。默认情况下,其他操作都可以通过这些方法之一获取流、执行某些操作,然后确保关闭流来实现的。
这些方法都被命名为:
openStream()
——根据源或接收器的类型返回InputStream
、OutputStream
、Reader
或Writer
。openBufferedStream()
——根据源或接收器的类型返回InputStream
、OutputStream
、BufferedReader
或Writer
。如果有必要,保证返回的流被缓冲。例如,从字节数组读取的源不需要在内存中进行额外缓冲。这就是为什么这些方法不返回BufferedInputStream
等的原因,除了在BufferedReader
的情况下,因为它定义了readLine()
方法。
2.2.2Source操作
ByteSource | CharSource |
---|---|
byte[]read() | Stringread() |
N/A | ImmutableList<String>readLines() |
N/A | StringreadFirstLine() |
longcopyTo(ByteSink) | longcopyTo(CharSink) |
longcopyTo(OutputStream) | longcopyTo(Appendable) |
Optional<Long>sizeIfKnown() | Optional<Long>lengthIfKnown() |
longsize() | longlength() |
booleanisEmpty() | booleanisEmpty() |
booleancontentEquals(ByteSource) | N/A |
HashCodehash(HashFunction) | N/A |
2.2.3Sink操作
ByteSink | CharSink |
---|---|
voidwrite(byte[]) | voidwrite(CharSequence) |
longwriteFrom(InputStream) | longwriteFrom(Readable) |
N/A | voidwriteLines(Iterable<?extendsCharSequence>) |
N/A | voidwriteLines(Iterable<?extendsCharSequence>,String) |
2.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));
3.Files
除了用于创建文件源和接收器的方法之外,Files
类还包含许多你可能感兴趣的便捷方法。
方法 | 描述 |
---|---|
createParentDirs(File) | 创建文件的必要但不存在的父目录。 |
getFileExtension(String) | 获取路径描述的文件的文件扩展名。 |
getNameWithoutExtension(String) | 获取已删除扩展名的文件的名称 |
simplifyPath(String) | 清理路径。并不总是与你的文件系统一致;仔细测试! |
fileTraverser() | 返回一个可以遍历文件树的Traverser |
本文参考:
IOExplained
guava-tests-io
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。