ByteStreams
and CharStreams
Guava uses the term "stream" to refer to a Closeable
stream for I/O data which has positional state in the underlying resource. The term "byte
stream" refers to an InputStream
or OutputStream
, while "char
stream" refers to a Reader
or Writer
(though their supertypes Readable
and Appendable
are often used as method parameter types). Corresponding utilities are divided into the utility classes ByteStreams
and CharStreams
.
Most Guava stream-related utilities deal with an entire stream at a time and/or handle buffering themselves for efficiency. Also note that Guava methods that take a stream do not close the stream: closing streams is generally the responsibility of the code that opens the stream.
Some of the methods provided by these classes include:
It's common to create I/O utility methods that help you to avoid dealing with streams at all when doing basic operations. For example, Guava has Files.toByteArray(File)
and Files.write(File, byte[])
. However, you end up with similar methods scattered all over, each dealing with a different kind of source of data or sink to which data can be written. For example, Guava has Resources.toByteArray(URL)
which does the same thing as Files.toByteArray(File)
, but using a URL
as the source of data rather than a file.
To address this, Guava has a set of abstractions over different types of data sources and sinks. A source or sink is a resource of some sort that you know how to open a new stream to, such as a File
or URL
. Sources are readable, while sinks are writable. Additionally, sources and sinks are broken down according to whether you are dealing with byte
or char
data.
The advantage of these APIs is that they provide a common set of operations. Once you've wrapped your data source as a ByteSource
, for example, you get the same set of methods no matter what that source happens to be.
Guava provides a number of source and sink implementations:
Bytes CharsFiles.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)
In addition, you can extend the source and sink classes yourself to create new implementations.
Note: While it can be tempting to create a source or sink that wraps an open stream (such as an InputStream
), this should be avoided. Your source/sink should instead open a new stream each time its openStream()
method is called. This allows the source or sink to control the full lifecycle of that stream and allows it to be usable multiple times rather that becoming unusable the first time any method on it is called. Additionally, if you're opening the stream before creating the source or sink you may still have to deal with ensuring that the stream is closed correctly if an exception is thrown elsewhere in your code, which defeats many of the advantages of using a source or sink in the first place.
Once you have a source or sink instance, you have access to a number of operations for reading or writing.
All sources and sinks provide the ability to open a new stream for reading or writing. By default, other operations are all implemented by calling one of these methods to get a stream, doing something, and then ensuring that the stream is closed.
These methods are all named:
openStream()
- returns an InputStream
, OutputStream
, Reader
or Writer
depending on the type of source or sink.openBufferedStream()
- returns an InputStream
, OutputStream
, BufferedReader
or Writer
depending on the type of source or sink. The returned stream is guaranteed to be buffered if necessary. For example, a source that reads from a byte array has no need for additional buffering in memory. This is why the methods do not return BufferedInputStream
etc. except in the case of BufferedReader
, because it defines the readLine()
method.// Read the lines of a UTF-8 text file ImmutableList<String> lines = Files.asCharSource(file, 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, 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));
In addition to methods for creating file sources and sinks, the Files
class contains a number of convenience methods that you might be interested in.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3