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 时间。每个线程遇到外部未准备好的时候,都会阻塞掉。阻塞的结果就是会带来大量的进程上下文切换。且大部分进程上下文切换可能是无意义的。比如一个线程监听一个端口,一天只会有几次请求进来,但是该 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的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值