瓜娃之走马观花 (3) - CharStreams和ByteStreams
程序员文章站
2022-07-14 14:44:12
...
其实guava可以看成是支持java5的apache commons之类的项目.
第一第二回讲的主要是集合类的一些最常用的工具. 其实com.google.common.collect里还有很多非常有用的工具, 比如Ordering, ComparisonChain, Iterables, Multiset, Multimap等等. 这里有些我们后面还会涉及.
小兄弟正在做socket客户服务器通信相关的课程设计, 所以我有点迫不及待先讲讲common.io这个包了. 这里面最有用的, 在我看来, 就是CharStreams和ByteStreams这两个工具.
大家知道, Java里读外设主要是跟InputStream和Reader打交道. 其中InputStream用来读取原始的字节流, 而Reader是在你已经知道了输入是用什么字符集编码的情况下读取字符串.
但是这两个类还是相对底层了一些. 在做一些很灵活复杂的事情的时候是必要的, 甚至我们还需要抬出nio这个大杀器. 可它们对日常工作中一些简单的事情, 就有炮弹打蚊子的感觉.
比如, 我需要从一个Reader里一行一行读出所有文本. 直接用Reader的话, 你需要弄一个BufferedReader, 然后循环调用readLine(), 直到全部读完. 类似这样:
用CharStreams的话, 一句话就搞定了:
如果你还是需要类似于流一样的操作-比如, 输入的行数太多, 不能一下子都读进来, 那么, 还有一个LineReader可以用. 用起来类似于:
其它的one-liner, 包括:
从一个Readable读取所有东西写到一个Appendable里去:
从Readable读取所有内容到一个字符串:
另外, 写io程序一个最常见的bug, 就是打开东西忘记关了. 或者关的不彻底. 一般来说, 你要开一个InputStream, 肯定要接下来用一个try-finally, 在用完之后调用close()把它关上. OutputStream, Reader, Writer同理.
但是这很麻烦, 而且容易忘. 在java7的自动资源管理出来之前, 可以用common.io包定义的InputSupplier, OutputSupplier接口.
原理是, 你实现一个InputSupplier对象, 把"怎样打开这个InputStream/Reader"的逻辑封装在getInput()它的函数里, 然后, 把它传递给CharStreams, ByteStreams相关的API, 比如readLines(), copy()等, 这些API调用你的supplier, 然后做事, 做完之后它把自己屁股擦干净, 把它打开的InputSteam/Reader再关上.
ByteStreams很类似, 不过它是工作在字节流上, 而不关心字符编码问题.
对应于CharStreams.toString(), 是
用来把整个InputStream的内容全部一次性读到一个byte[]里面.
对应于CharStreams.copy(), 是
用来把所有内容从一个InputStream拷贝到另一个OutputStream.
嗯. 以上.
第一第二回讲的主要是集合类的一些最常用的工具. 其实com.google.common.collect里还有很多非常有用的工具, 比如Ordering, ComparisonChain, Iterables, Multiset, Multimap等等. 这里有些我们后面还会涉及.
小兄弟正在做socket客户服务器通信相关的课程设计, 所以我有点迫不及待先讲讲common.io这个包了. 这里面最有用的, 在我看来, 就是CharStreams和ByteStreams这两个工具.
大家知道, Java里读外设主要是跟InputStream和Reader打交道. 其中InputStream用来读取原始的字节流, 而Reader是在你已经知道了输入是用什么字符集编码的情况下读取字符串.
但是这两个类还是相对底层了一些. 在做一些很灵活复杂的事情的时候是必要的, 甚至我们还需要抬出nio这个大杀器. 可它们对日常工作中一些简单的事情, 就有炮弹打蚊子的感觉.
比如, 我需要从一个Reader里一行一行读出所有文本. 直接用Reader的话, 你需要弄一个BufferedReader, 然后循环调用readLine(), 直到全部读完. 类似这样:
BufferedReader buffered = new BufferedReader(reader); List<String> lines = new ArrayList<String>(); for (;;) { String line = buffered.readLine(); if (line == null) { break; } lines.add(line); }
用CharStreams的话, 一句话就搞定了:
List<String> lines = CharStreams.readLines(reader);
如果你还是需要类似于流一样的操作-比如, 输入的行数太多, 不能一下子都读进来, 那么, 还有一个LineReader可以用. 用起来类似于:
LineReader lineReader = new LineReader(reader); for (String line = lineReader.readLine(); line != null; line = lineReader.readLine()) { System.out.println(line); }
其它的one-liner, 包括:
从一个Readable读取所有东西写到一个Appendable里去:
CharStreams.copy(reader, writer);
从Readable读取所有内容到一个字符串:
String content = CharStreams.toString(reader);
另外, 写io程序一个最常见的bug, 就是打开东西忘记关了. 或者关的不彻底. 一般来说, 你要开一个InputStream, 肯定要接下来用一个try-finally, 在用完之后调用close()把它关上. OutputStream, Reader, Writer同理.
但是这很麻烦, 而且容易忘. 在java7的自动资源管理出来之前, 可以用common.io包定义的InputSupplier, OutputSupplier接口.
原理是, 你实现一个InputSupplier对象, 把"怎样打开这个InputStream/Reader"的逻辑封装在getInput()它的函数里, 然后, 把它传递给CharStreams, ByteStreams相关的API, 比如readLines(), copy()等, 这些API调用你的supplier, 然后做事, 做完之后它把自己屁股擦干净, 把它打开的InputSteam/Reader再关上.
ByteStreams很类似, 不过它是工作在字节流上, 而不关心字符编码问题.
对应于CharStreams.toString(), 是
byte[] content = ByteStreams.toByteArray(inputStream)
用来把整个InputStream的内容全部一次性读到一个byte[]里面.
对应于CharStreams.copy(), 是
ByteStreams.copy(inputStream, outputStream);
用来把所有内容从一个InputStream拷贝到另一个OutputStream.
嗯. 以上.