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

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

一个允许你反悔的hook

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

BufferedInputStream in  =   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、付费专栏及课程。

余额充值