IO流
-
流(stream):一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象,对文件中的内容读和写的操作。
-
及时关闭不使用的流,避免造成资源流失,可能会导致内存溢出
数据流向
输入流: 负责数据的读取
例:从服务器读取数据,下载
InputStream 抽象类(子类:FileInputStream/BufferedInputStream)
Reader 抽象类(子类:InputStreamReader/BufferedReader)
输入流: 数据的写入
例:上传文件
OutputStream 抽象类(子类:FileOutStream/BufferedOutputStream)
Writer 抽象类(子类:OutputStreamWriter/BufferedWriter)
数据类型
字符流: 处理字符,根据码表映射字符,一次可能读多个字节 一次读入或读出16位二进制
Reader / Writer
字节流: 处理字节 一次读入或读出8位二进制
InputStream / OutputStream
总结
IO采用的是装饰模式,即采用处理流包装节点流的方式来达到代码通用性
处理流和节点流的区分方法:
节点流在新建时需要一个数据源(文件、网络)作为参数
作用:提高代码通用性,编写代码的便捷性,提高性能
处理流需要一个节点流作为参数
作用:对应抽象基类的实现类,他们都实现了抽象基类的基础读写方法Read()方法,若返回-1,代表已经读到数据源末尾
常用流
对文件进行操作:FileInputStream(字节输入流)
FileOutputStrean(字节输出流)
FileReader(字符输入流)
FileWriter(字符输出流)
对管道进行操作:PipedInputStream(字节输入流)
PipedOutStream(字节输出流)
PipedReader(字符输入流)
PipedWriter(字符输出流)
字节/字符数组:ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter是带缓冲区的处理流
作用:避免每次和硬盘打交道,提高数据访问的效率
数据流:DataInputStream
DataOutputStream
作用:可以直接输出float类型和long类型,提高了数据读写的效率
随机访问文件:RandomAccessFile
Buffered缓冲流:BufferedInputStream
BufferedOutputStream
CharArrayReader
CharArrayWriter实在内存中开辟了一个字节或字符数组
场景
文件传输(复制文件,删除文件或文件夹,文件改名等)
网络传输(从服务器进行数据读取,上传下载等)
硬盘数据的存储
NIO流
由来
传统的IO流有很多缺陷,尤其阻塞性加上磁盘写本来就慢,会导致cpu使用效率大大降低
所以,JDK1.4发布了NIO包,采用通道+缓冲区,使得新式的IO操作直接面向缓存区,并非阻塞的,提高程序的性能,提升cpu的利用率
例:计算机的处理速度和用户按键盘的速度
NIO的简述
主要有三大核心部分:
通道(Channel,是一个对象,可以通过他来读取和写入数据)
缓冲区(Buffer,是一个对象,包含一些要写入或者刚读出的数据)
选择区(Selector能检测到多个NIO通道,并能够知晓通道是否为读写事件做好准备,这样一个单独的线程可以管理多个channel,从而管理多个网络连接)
数据从通道读取到缓冲区中,或者缓冲区写入到通道中。
选择区用于监听多个通道事件(例:连接打开,数据到达),因此单个线程可以监听多个数据通道
为所有的原始类型(boolean类除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络,主要解决了多线程的问题
特性:分散与聚焦读取
文件锁定功能
网络异步IO
注意事项
SelectionKey用完一定要移除
SelectionKey.open()不是线程安全的,可能会抛出NullPointerException
如果一个selection thread已经在select方法上等待,那么这个时候如果有另一个线程调用channal.register方法的话,那么他将被blocking
selectionKay.cancel() BUG导致CPU占用100%
!!!使用JDK6 U4以上版本不会出现以上BUG(除SelectionKey.open()不是线程安全以外)
场景
用于管理线程的并发数 读取大文件速度快
IO/NIO区别
IO | NIO |
---|---|
面向流 | 面向缓冲 |
阻塞IO | 非阻塞IO |
使用流处理数据 | 使用块处理数据 |
选择器 |
- 面向流与面向缓冲区
IO是面向流的,直至读取所有字节,他们没有被缓存在任何地方。此外,他不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将他缓存到一个缓冲区 - 阻塞与非阻塞IO
IO的各种流是阻塞的。意味着,当一个线程调用read()或write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情
NIO是非阻塞模式的,当一个线程从某通道发送请求读取数据时,他仅能得到目前可用数据,如果目前没有数据可用,就什么都不做。而不是保持线程阻塞,所以直至数据可以读取之前,该线程可以继续做其他事情 - 选择器
IO没有选择器
NIO的选择器允许一个单独的线程来监视多个输入通道,可以注册多个通道使用一个选择器,然后使用一个单独的线程来”选择”通道