分享
 
 
 

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

王朝java/jsp·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

jungleford如是说 PushbackInputStreamPushbackReaderJava I/O系统里两个比较让人迷惑的类,我以前对它(们)就不太了解,直到某一天看了以前水母Java版的牛人zms的评论和一些资料以后才有所获益。这是几个月以前的事情了,这几天写有关序列化的总结时才想到这也不失为一个好的话题。

一个允许你反悔的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是另一种情况),如果你以前奇怪为什么数据库操作中ResultSet里get某个字段以后就不能再第二次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缓冲前面一段内容,等取到字符集名称后在把读到的流全部归还,再用指定的字符集进行解析。

参考资料

Java Network Programming. by Elliotte R. Harold zms兄在水母的帖子. by zms(无奈的是,水木清华已经不能对校外开放了) JDK 1.4.2 Documentation. by java.sun.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有