Java IO

第一部分 Java IO

Java流和字节流转换处理字符流。字符流处理单元2字节Unicode字符。操作字符、字符数组或字符串,而字节流处理单元为1个字节。操作字节和字节数组。

以字节为单位的Stream:InputStream、OutputStream

InputStream,此抽象类是字节输入流的全部类的超类(把xxx作为输入的来源,从中读取数据)。OutputStream。此抽象类是输出字节流的全部类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

操作对象是字节(或字节数组)。所以String须要调用getBytes()转换后才干进行操作。操作的时候,能够选择一个字节一个字节的操作。也能够选择多个字节一起操作。

ByteArrayInputStream    --- 把内存中的一个缓冲区作为InputStream使用
FileInputStream              --- 把一个文件作为InputStream,实现对文件的读取操作
StringBufferInputStream --- 把一个String 对象作为 InputStream
PipedInputStream           --- 实现了 pipe 的概念,管道输入流是指一个通讯管道的接收端。

一个线程通过管道输出流发送数据,而还有一个线程通过管道输入流读取数据。这样可实现两个线程间的通讯。


ByteArrayOutputStream --- 把信息存入内存中的一个缓冲区中。该类实现一个以字节数组形式写入数据的输出流
FileOutputStream           --- 文件输出流是向File或FileDescriptor输出数据的一个输出流

以字符为单位向的Stream:Reader、Writer

CharArrayReader --- 与ByteArrayInputStream相应,此类实现一个可用作字符输入流的字符缓冲区
StringReader        --- 与StringBufferInputStream相应,其源为一个字符串的字符流
FileReader            --- 与FileInputStream 相应

转换:InputStreamReader、OutputStreamReader

把一个以字节为导向的stream转换成一个以字符为导向的stream。
InputStreamReader类是从字节流到字符流的桥梁:它读入字节。并依据指定的编码方式。将之转换为字符流(编码方式能够指定,或使用平台默认的编码方式)。为了达到更高效率。考虑用BufferedReader封装:BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

考虑的顺序:数据格式(字节/字符)→输入/输出→是否须要转换→数据来源/去向(文件、Byte[]、Char[]、String)→是否须要缓冲(须要BufferedInputStream/BufferedReader)→是否须要格式化输出(须要PrintStream/PrintWriter)

字节流和字符流的差别
实际上字节流在操作的时候本身是不会用到缓冲区的。是文件本身直接操作的,可是字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件的。假设将字节流和字符流程序关闭文件的代码凝视掉,你会发现使用字节流的话,写入后文件里内容就存在了,可是使用字符流的话,文件里还是没有内容的,须要刷新缓冲区才会有。

字节流和字符流哪个更好?
答案是字节流。由于硬盘上的全部文件都是以字节的形式进行传输或者保存的,包含图片等内容,字符是在内存中形成的。


第二部分 Java NIO

NIO非堵塞IO(Nonblocking IO)

1、堵塞式IO:多线程处理多个连接。

每一个线程拥有自己的栈空间而且占用一些 CPU 时间。每一个线程遇到外部未准备好的时候,都会堵塞掉。堵塞的结果就是会带来大量的进程上下文切换。

且大部分进程上下文切换可能是无意义的。比方一个线程监听一个port,一天仅仅会有几次请求进来,可是该 cpu 不得不为该线程不断做上下文切换尝试。大部分的切换以堵塞告终。

非堵塞IO:由一个专门的线程来处理全部的 IO 事件。并负责分发。事件到的时候触发。而不是像堵塞式那样同步的去监视事件。

保证每次上下文切换都是有意义的。

2、重要API
Selector,异步 IO 的核心类。它能检測多个通道 (channel) 上的事件,并将事件分发出去。使用一个 select 线程就能监听多个通道上的事件,并基于事件驱动触发对应的响应。

而不须要为每一个channel 去分配一个线程。


SelectionKey,包括了事件的状态信息和时间相应的通道的绑定。

Channel。Java NIO的通道类似流。但又有些不同: 
①.既能够从通道中读取数据,又能够写数据到通道。但流的读写一般是单向的。

 
②.通道能够异步地读写。

 
③.通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。 从通道读取数据到缓冲区,从缓冲区写入数据到通道。

Buffer,Java NIO中的Buffer用于和通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。

 缓冲区本质上是一块能够写入数据。然后能够从中读取数据的内存。

这块内存被包装成NIO Buffer对象。并提供了一组方法,用来方便的訪问该块内存。

使用Buffer读写数据一般有下面4个步骤: 
①.写入数据到Buffer。Buffer会记录写了多少数据
②.调用flip()方法。反转此缓冲区。(首先将限制设置为当前位置。然后将位置设置为 0)
③.从Buffer中读取数据
④.调用clear()方法或者compact()方法。一旦读完了全部的数据。就须要清空缓冲区。让它能够再次被写入。

clear()方法会清空整个缓冲区。compact()方法仅仅会清除已经读过的数据,不论什么未读的数据都被移到缓冲区的起始处。


第三部分 Java IO和NIO的差别

1、面向流与面向缓冲 
Java IO是面向流的,NIO是面向缓冲区的。Java IO面向流意味着每次从流中读一个或多个字节。直至读取全部字节,它们没有被缓存在不论什么地方。此外,它不能前后移动流中的数据。

假设须要前后移动从流中读取的数据,须要先将它缓存到一个缓冲区。 

2、堵塞与非堵塞
Java IO的各种流是堵塞的。当一个线程调用read() 或 write()时,该线程被堵塞。直到有一些数据被读取,或数据全然写入。该线程在此期间不能再干不论什么事情了。

Java NIO的非堵塞模式。使一个线程从某通道发送请求读取数据,可是它仅能得到眼下可用的数据,假设眼下没有数据可用时,就什么都不会获取。而不是保持线程堵塞,所以直至数据变的能够读取之前,该线程能够继续做其他的事情。

非堵塞写也是如此。线程通常将非堵塞IO的空暇时间用于在其他通道上运行IO操作,所以一个单独的线程如今能够管理多个输入和输出通道(channel)。

 

3、选择器(Selectors) 
Java NIO的选择器同意一个单独的线程来监视多个输入通道,你能够注冊多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有能够处理的输入,或者选择已准备写入的通道。这样的选择机制,使得单个线程非常easy要管理多渠道。

版权声明:本文博主原创文章。博客,未经同意不得转载。

原文地址:https://www.cnblogs.com/bhlsheji/p/4884531.html