【转】“给你第二次机会”——小议PushbackInputStream

PushbackInputStreamPushbackReaderJava I/O系统 里两个比较让人迷惑的类。

一个允许你反悔的hook

Java I/O系统是一个典型的Decorator模式的实现,它以InputStream/OutputStream为基本核心,通过继承关系,不断为该核心添加新的功能,如文件流、缓冲、加解密等。对I/O系统设计模式感兴趣的话,可以参考developerWorks上的一篇文章:从Java类库看设计模式Java I/O默认是不缓冲流的,所谓缓冲就是先把从流中得到的一块字节序列暂存在一个被称为buffer的内部字节数组里,然后你可以一下子取到这一整块的字节数据,没有缓冲的流只能一个字节一个字节读,效率孰高孰低一目了然。有两个特殊的输入流实现了缓冲功能,一个是我们常用的BufferedInputStream,像读文件我们常用

BufferedInputStreamin = new BufferedInputStream( new FileInputStream( " datafile " ));
while ((b = in.read()) != - 1 )
{

}

in.close();

这是我们几乎不用查什么 JDK文档 就能信手拈来的代码段,写的时候也应该思考一下套一个 BufferedInputStream 的意义何在。另一个就是我们不怎么看到的 PushbackInputStream (其对应的字符流模式为 PushbackReader )。
在通常状态下, 意味着 一次性 ,就是说你进行了一次操作后它的状态就变了,譬如读,无论是文件还是 socket ,你读的过程中一个潜在的 读指针 一样的东东就在移动,你无法在读以后再重新定位(当然 RandomAccessFile 是另一种情况),如果你以前奇怪为什么数据库操作中 ResultSetget 某个字段以后就不能再第二次 get 它了,这里或许是个解释。但好在 PushbackInputStream 给了我们第二次读的机会。我们先来区别一下 监听 截获 的概念, 监听 就是把得到的消息 copy 一份,原始消息并不作任何改变地传递到目的地;而 截获 则是先把消息 扣押 下来,不让其自动转给目标,而是先进行一些处理以后在转发给目标(如果是网络安全专业的背景知识,大概知道 监听 是对 机密性 的攻击,而 截获 不仅是对 机密性 还是对 完整性 的攻击)。有的朋友大概对 hook 这个名词有些了解,它是一种 Windows 的一种消息处理机制,似乎就是一种消息截获手段,但我对 Windows 编程一窍不通 //shy ;此外,如果你熟悉 Servlet 的话,也能找到像 Filter 这样的处理机制,在对每个 HTTP 请求 / 应答进行转发之前,先在里头耍一点花招,确定哪些予以转发,哪些屏蔽掉,这也算是 截获 吧。通过上面的介绍,我们不妨把 PushbackInputStream 看成是对输入流的一种 截获 手段,其中最重要的方法是 unread
public void unread( int b) throws IOException
public void unread( byte []b) throws IOException
public void unread( byte []b, int off, int len) throws IOException
我们可以想象一下, PushbackInputStream 内置一个缓冲区(事实上,你可以从它的源代码里找到这个 protected 的字节数组),当低层流进来时先流进这个 buffer ,在你把流 物归原主 之前还有机会对它耍花招,然后再用 unread 方法 反悔 一下,把缓冲区里已经读过的内容(一般是没有被改动的,当然你也可以改动它,那就失去 归赵 的意义了,因为已经不是 完璧 了)再插入到流的头部,下次读的时候是流剩余的部分再加上从缓冲区 归还 的部分。上面三个 unread 方法分别代表从缓冲区 归还 一个字节、一个字节数组以及一个字节数组中指定的部分。
PushbackInputStream
是对二进制流的处理,字符流下相对应的就是 PushbackReader

有什么用?

学过编译的话就容易理解了,比如从左向右扫描字符流“for(int i=0;i<10;i++)”,扫描到“for”是不是就可以说是个关键字了呢?不行,说不定后面是“for1”,那就是个变量而不是关键字了,知道看到“(”才恍然大悟,哦,我可以安全地说看到for关键字了,但“(”还得归还给输入流,因为需要后面继续扫描。在上下文相关语言里,就更需要这种补偿机制。又如,在解析HTML文档的时候,我需要根据它的“meta”标签的“charset”属性来决定使用哪种字符集进行解析,但HTML可不是“charset”而是“<html>”开头的哦!所以需要通过PushbackInputStream缓冲前面一段内容,等取到字符集名称后在把读到的流全部归还,再用指定的字符集进行解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值