2023-08-17
原文作者:LifeIsForSharing 原文地址:https://solang.blog.csdn.net/article/details/105101316

I/O:针对Java 5和6版本的简化的I/O操作,尤其是在整个I/O流和文件上。

1.ByteStreamsCharStreams

Guava使用术语“流”来表示在底层资源中具有位置状态I/O数据的Closeable流。术语"字节流"是指InputStreamOutputStream,而"字符流"是指ReaderWriter(尽管它们的超类型ReadableAppendable通常用作方法参数类型)。相应的工具分为工具类ByteStreamsCharStreams

大多数与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对不同类型的数据源和接收器提供了一组抽象。源或接收器是你知道如何打开新流的某种资源,例如FileURL。源是可读的,而接收器是可写的。此外,根据你要处理的是字节数据还是字符数据,还细分了源和接收器。

 操作   字节   字符 
 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()——根据源或接收器的类型返回InputStreamOutputStreamReaderWriter
  • openBufferedStream()——根据源或接收器的类型返回InputStreamOutputStreamBufferedReaderWriter。如果有必要,保证返回的流被缓冲。例如,从字节数组读取的源不需要在内存中进行额外缓冲。这就是为什么这些方法不返回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

阅读全文