`
kidiaoer
  • 浏览: 822275 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论
阅读更多
IO/NIO学习总结


【1.什么是InputStream?InputStream类结构?】

首先学习基类java.io.InputStream(读取一系列字节的对象),以及在它基础上派生出来的子类,类结构图如上图所示。InputStream是一个抽象类,是所有数据形式为字节的输入流的父类,为基于字节的数据输入定义了基本操作方法。实际上,InputStream的子类大部分都没有增加任何其他的接口函数(在上面的类结构图中就可以发现),因此在看InputStream子类的时候,我们主要学习其构造函数。

PushbackInputStream 向另一个输入流添加“推回 (push back)”或“取消读取 (unread)”一个字节的功能。这在以下情况下非常有用,即代码片段可以很方便地读取由特定字节值分隔的不定数量的数据字节;在读取终止字节后,该代码片段可以“取消读取”该字节,这样,输入流上的下一个读取操作将会重新读取被推回的字节。例如,表示构成标识符的字符的字节可能由表示操作符字符的字节终止;其作业只是读取标识符的方法可以进行读取,直到该操作看到此操作符,然后将该操作符推回以进行重读。

1.2.1 PushbackInputStream

“给你第二次机会”——小议PushbackInputStream, 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(); 

在通常状态下,“流”意味着“一次性”,就是说你进行了一次操作后它的状态就变了,譬如读,无论是文件还是socket,你读的过程中一个潜在的“读指针”一样的东东就在移动,你无法在读以后再重新定位(当然RandomAccessFile是另一种情况),如果你以前奇怪为什么数据库操作中ResultSet里get某个字段以后就不能再第二次get它了,这里或许是个解释。但好在PushbackInputStream给了我们第二次读的机会。

我们先来区别一下“监听”和“截获”的概念,“监听”就是把得到的消息copy一份,原始消息并不作任何改变地传递到目的地;而“截获”则是先把消息“扣押”下来,不让其自动转给目标,而是先进行一些处理以后在转发给目标(如果是网络安全专业的背景知识,大概知道“监听”是对“机密性”的攻击,而“截获”不仅是对“机密性”还是对“完整性”的攻击)。有的朋友大概对hook这个名词有些了解,它是一种Windows的一种消息处理机制,似乎就是一种消息截获手段,但我对Windows编程一窍不通。

此外,如果你熟悉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缓冲前面一段内容,等取到字符集名称后在把读到的流全部归还,再用指定的字符集进行解析。

【2.Java I/O中是如何采用Decorator(装饰)模式的呢?】

答:下面为大家详细说明,看到FilterInputStream类(也就前面说的过滤流,后面你会发现更多的过滤流),你是否发现了?对,就是 FilterInputStream类,她就相当于Decorator(装饰)模式中的Decorator类,而且的 BufferedInputStream、DataInputStream、PushbackInputStream则相当于是 ConcreateDecorator,如下图为Decorator模式结构图所示:

那么Java I/O中到底是如何使用的了?Decorator(装饰)模式的主要意图是:动态地给一个对象添加一些额外的职责,这句话很抽象,我们结合Java I/O举个具体的例子:比如说我们读取文件,首先打开文件获取到File,然后我们再创建一个FileInputStream,然后读取文件。读取文件是一个很费时的操作,尤其是需要多次的读写文件。

Decorator模式的设计动机:有时希望给某个对象增加而不是整个类增加一些功能,例如,给一个图像界面工具箱允许你对人员一个用户界面的组件添加一些特性,比如说边框,或者窗口滚动。使用继承机制是添加功能的一种有效途径,从其他类继承过来的边框特性可以被多个子类的实例所实现。但是这种方法不够灵活,因为边框的选择是静态的,用户不能控制对组件加边框的方式和时机。

一种较为灵活的方式是将组件嵌入另外一个对象中,由这个对象添加边框,我们称这个嵌入的对象为装饰。

在Java中采用OOP:BufferedInputStream实现了对数据读取的缓冲机制,通过FileInputStream来读取数据,BufferedInputStream将已经读取的数据存储到缓冲区,BufferedInputStream相当于对 FileInputStream进行了“装饰”。

Decorator示例代码如下:

File file = new File(“c:\\moandroid.txt”,true);
InputStream is = new BufferedInputStream(new FileInputStream(file));
long length = file.length();
if(length>Integer.MAX_VALUE){
System.out.println(“source file is too large”);  return ;
}
byte[] bytes = new byte[(int)length];
int offset = 0,numRead = 0;
while( offset<bytes.length && (numRead = is.read(bytes,offset,bytes.length-offset))>= 0)
offset += numRead;
if(offset<bytes.length)

throw new IOException(“Could not completely read file”+file.getName());
is.close();

DataInputStream类的功能则更加强大,其在InputStream类的基础上增加了很多读取函数的接口,举个例子如下:

DataInputStream:增加了读取JAVA基本数据类型的功能。

BufferedInputStream:增加了缓冲的功能。

InputStream is = null;
try{
File file = new File(“c:\\moandroid.txt”,true);
is = new DataInputStream(new FileInputStream(file));
int intData = is.readInt();
boolean boolData = is.readBoolean();
}catch(FileNotFoundException e) { e.printStackTree();}
catch(IOException e){ e.printStackTree(); }
finally{  if(is!=null){ try{is.close();} catch(IOException e){} }}

PS:DataInputStream读取的顺序必须和实际数据存储的顺序一致,否则会出现IOException。

1.3 OutputStream及其Family:

【1.什么是OutputStream?OutputStream类结构图?】

和InputStream类似,OutputStream(写入一系列字节的对象)是所有字节形式输出流的类。 java.io.InputStream/OutputStream的类结构中可以找到相互对应的类,这里额外需要说明的是PrintStream 类。

实际上标准输出流:System.out的类型就是java.io.PrintStream。PrintStream作为FilterOutputStream的子类,其作用也是将某个输出流再次封装,并且提供了一些新的输出特性。其他标准输出:System.in的类型是InputStream,其默认是由JRE指向系统的标准输入流,在控制台下默认是键盘的输入,使用in.read()方法,将返回用户键盘输入的值;System.err的类型也是 java.io.PrintStream。

下面举个具体的例子来说明,如何实现重定向标准输入/输出:

PrintStream output = new PrintStream(new FileOutputStream(“c:/out.log”));
System.setOut(output);

PrintStream errOutput = new PrintStream(new FileOutputStream(“c:/err.log”));
System.setErr(errOutput);

System.out.println(“Output redirect test”);
System.err.println(“Error redirect test”);

原来在控制台输出的文字都将被写入out.log或err.log文件中。

1.4 Reader及其Family?

【7.什么是Reader?Reader类结构图?】

InputSteream和OutpurStream是针对基于字节(byte)输入输出设计的,应用中常需要读写的是基于字符(char ,Unicode 2个字节)的,java.io.Reader和java.io.Writer就是所有读写字符数据流的父类。Reader提供的方法和InputStream提供的几乎是一样的,不同之处在于Reader的操作多数是char类型的。

对上图(从下往上看)总结说明如下:

· Reader类中定义了成员变量lock,顾名思义,lock的用途是解决实现对流操作的同步问题。Reader的子类可以使用这个成员变量来实现流操作的同步操作。

· FilterReader也是采用了Decorator(装饰)模式,与我们在前面学习InputStream、OutputStream相比较,如下图所示:

前面的 BufferedInputStream、BufferedOutputStream都是采用了Decorator(装饰)模式,而这里的 BufferedReader是直接从Reader继承下来了,而不是从F ilterReader继承的,不符合Decorator(装饰)模式据说这个JAVA SDK中的一个BUG,但是好像一直也没有修改,估计对使用没有大的影响吧。此外BufferedReader还提供了一个String readLine()函数,方便我们从文件中读取一行数据,这个函数也是比较有用的。

· InputStreamReader就像是一个桥:把字节流(byte)转换为字符流(char),它读取字节流,并使用指定的字符集(charset) 将这些字节流转换为字符。常见的字符集有:GBK、ISO-8859-1、UTF-8,Java的字符流本身采用的就是Unicode,关于字符集的详细说明请看文档。例子如下:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String strLine;
while(strLine=in.readline()!=null){
System.out.println(strLine);
}
in.close();
具体的含义就是:将标准输入流转换为字符流,并缓存到BufferedReader的缓冲区中,并将缓冲区中的数据显示在标准输出设备上。

总结说明

Reader子类中较常用的还是:BufferedInputStream、InputStreamReader,BufferedInputStream为我们提供了数据缓存机制,对于读取大块的数据比较方便,尤其是在读取文件的时候;InputStreamReader作为流的转换,转换后的字符流是什么编码,与虚拟机默认的字符集有关,关于字符集部分大家还需要去深入学习。
分享到:
评论

相关推荐

    JAVA_IO/NIO(demo,压缩jar文件)

    在Java编程语言中,`IO`(Input/Output)和`NIO`(Non-blocking Input/Output)是处理数据输入和输出的关键技术。本压缩包包含`JAVA_IO/NIO(demo,压缩jar文件)`,意味着它提供了一些示例代码,用于演示如何使用这两...

    NIO学习总结经典

    《NIO学习总结经典》这篇文章主要探讨了Java的New IO(NIO)框架,这是一个用于高效处理I/O操作的重要库,特别是在处理大量并发连接时。NIO与传统的IO(-blocking I/O)相比,提供了非阻塞的I/O模型,极大地提高了...

    JAVA_NIO学习总结

    ### JAVA_NIO学习总结 #### 重要知识点概览 JAVA_NIO(Non-blocking I/O,非阻塞I/O)是Java平台中用于替代传统IO(Blocking IO)的一种高性能IO处理模型,首次出现在JDK 1.4中。NIO通过引入通道(Channel)和缓冲区...

    java IO NIO AIO.xmind

    涉及到java io, nio, aio相关知识点,学习过程中的一些总结,持续更新中,xmind 格式

    NIO学习与总结

    ### NIO学习与总结 #### 一、NIO概述与核心概念 **NIO(New IO)**,即新输入/输出技术,是Java 1.4版本开始引入的一种新的I/O处理方式,旨在提高Java应用程序的I/O处理效率。与传统的基于流的I/O相比,NIO更加...

    《JAVA_IO流学习总结》

    总结来说,Java IO流是一个庞大的体系,覆盖了从基础的文件操作到复杂的网络通信,理解并熟练掌握这一部分将极大地提升Java开发者的技能。通过学习和实践,开发者可以灵活地处理各种数据输入输出场景,为应用程序...

    t-io百万级网络框架 v3.8.5.zip

    《t-io百万级网络框架 v3.8.5:打造高效稳定的网络通信》 t-io是一个高性能、轻量级的网络通信框架...对于学习和研究网络编程、提升系统性能的开发者而言,深入理解并掌握t-io框架,无疑会极大地提升自身的专业技能。

    Java_NIO与IO的区别和比较.doc

    Java NIO(New Input/Output)是Java标准库在J2SE 1.4及以后版本中引入的一个重要更新,旨在提供更高效、更灵活的I/O操作。相比于传统的IO(Input/...然而,NIO的API相对复杂,理解和使用起来需要一定的学习成本。

    Java学习之IO总结及mina和netty

    这篇博客“Java学习之IO总结及mina和netty”探讨了Java IO的基础知识,并深入到两个高级网络通信框架——Mina和Netty。Mina和Netty都是基于NIO(非阻塞IO)的高性能网络应用框架,它们简化了复杂网络编程的实现。 *...

    Java技术总结第一章.svg

    这一节主要整理网关泛化调用、java管道技术、IO/NIO、Netty以及异步骤处理相关支持,整理为导图,把学习中的关键技术点整理出来,同时参考的文章给大家一并整理好

    Java /io总结 很不错

    本文将对Java I/O进行详细的总结,包括基本概念、流的分类、缓冲区、转换流以及高级特性。 首先,理解Java I/O的基础是“流”。在Java中,流是一个数据序列,可以是字节流或字符流,用于读取或写入数据。流分为四大...

    JavaIO流学习总结报告.doc

    虽然本报告主要讨论了基础的IO流,但了解NIO也是Java IO学习的重要部分。 总之,Java IO流是处理输入输出的核心工具,理解字节流与字符流的区别、流的层次结构以及基本操作方法,对于进行文件读写、网络通信等任务...

    JavaNIO浅析IO模型Java开发Java经验技巧共1

    总结,Java NIO是一个强大的工具,它改变了Java处理I/O的方式,提升了并发性能。理解和掌握NIO,对于任何Java开发者来说,都能在开发高性能应用时游刃有余。在实际开发中,结合具体需求,灵活运用NIO,可以极大地...

    javaNIO学习笔记

    ### Java NIO 学习笔记 #### 一、概述 Java NIO (Non-Blocking IO,也称为 Java New IO),是 Java 对传统 IO 模型的一次重大改进,旨在提高程序处理大量并发连接的能力。NIO 的核心组件包括 Channels、Buffers 和 ...

    bio-nio-aio.zip

    总结,Java IO的发展经历了从BIO到NIO的转变,再到Reactor模式的优化,每一步都是为了提高系统的并发处理能力和资源利用率。理解并熟练掌握这些IO模型,对于开发高效、稳定的服务器端程序至关重要。通过对压缩包中的...

    javaio流学习总结范文.doc

    本篇总结主要围绕Java IO流的基础概念、分类以及常用方法展开。 首先,Java IO流按照数据流动的方向可分为输入流(Input Stream)和输出流(Output Stream)。输入流负责从源(如文件、网络连接)读取数据,而输出...

    JavaNIO与IO的区别和比较.pdf

    总结来说,Java NIO相比于传统的IO,提供了更为灵活和高效的I/O操作方式,特别适合于处理高并发、低延迟的网络应用,如服务器端的开发。学习和掌握NIO对于Java开发者来说,能提升在系统级编程和网络编程领域的专业...

    一份超级详细的Java面试题【大厂面试真题+Java学习指南+工作总结】.zip

    Java作为一款广泛应用的编程语言,其面试题涵盖了多个层面的知识,包括基础语法、数据结构与算法、多线程、集合框架、JVM内存管理、异常处理、IO/NIO、网络编程、设计模式以及框架应用等。下面将针对这些关键领域...

Global site tag (gtag.js) - Google Analytics