14. Java中的IO流
按功能划分: 输入流 InputStream和 输出流 OutputStream
按类型划分: 字符流 和 字节流
1. InputStream
inputstream 基类
- available():返回stream中的可读字节数,inputstream类中的这个方法始终返回的是0,这个方法需要子类去实现。
- close():关闭stream方法,这个是每次在用完流之后必须调用的方法。
- read():方法是读取一个byte字节,但是返回的是int。
- read(byte[]):一次性读取内容到缓冲字节数组
- read(byte[],int,int):从数据流中的哪个位置offset开始读长度为len的内容到缓冲字节数组
- skip(long):从stream中跳过long类型参数个位置
- mark(int):用于标记stream的作用
- markSupported():返回的是boolean类型,因为不是所有的stream都可以调用mark方法的,这个方法就是用来判断stream是否可以调用mark方法和reset方法
- reset():这个方法和mark方法一起使用的,让stream回到mark的位置。
BufferedInputStream类调用mark(int readlimit)方法后读取多少字节标记才失效,是取readlimit和BufferedInputStream类的缓冲区大小两者中的最大值,而并非完全由readlimit确定,
1.1ByteArrayInputStream
ByteArrayInputStream -- 把内存中的一个缓冲区作为 InputStream 使用 .
construct---
(A)ByteArrayInputStream(byte[]) 创建一个新字节数组输入流( ByteArrayInputStream ),它从指定字节数组中读取数据( 使用 byte 作为其缓冲区数组)
(B)ByteArrayInputStream(byte[], int, int) 创建一个新字节数组输入流,它从指定字节数组中读取数据。
1.2StringBufferInputStream
StringBufferInputStream(String) 据指定串创建一个读取数据的输入流串。
不推荐,推荐使用StringReader 创建字符串输入流
1.3 FileInputStream
把一个文件作为 InputStream ,实现对文件的读取操作
construct—
(A)FileInputStream(File name) 创建一个输入文件流,从指定的 File 对象读取数据。
(B)FileInputStream(FileDescriptor) 创建一个输入文件流,从指定的文件描述器读取数据。
(C)-FileInputStream(String name) 创建一个输入文件流,从指定名称的文件读取数据。
额外实现
getChannel():这个方法返回一个FileChannel对象,这个主要用于JNIO中的通道的。
getFD():这个方法返回一个FileDescriptor对象,这个在构造函数中使用过。1.4 PipedInputStream
实现了 pipe 的概念,主要在线程中使用 . 管道输入流是指一个通讯管道的接收端。
一个线程通过管道输出流发送数据,而另一个线程通过管道输入流读取数据,这样可实现两个线程间的通讯。
construct—
PipedInputStream() 创建一个管道输入流,它还未与一个管道输出流连接。
PipedInputStream(PipedOutputStream) 创建一个管道输入流 , 它已连接到一个管道输出流。1.5 SequenceInputStream
把多个 InputStream 合并为一个 InputStream . “序列输入流”类允许应用程序把几个输入流连续地合并起来,
并且使它们像单个输入流一样出现。每个输入流依次被读取,直到到达该流的末尾。1.6 ObjectInputStream
用于操作Object的stream,这个在stream主要用在对象传输的过程中,其中牵涉到了序列化的知识
常用方法 readObject将一个对象写入到stream中,但是这个object必须序列化1.7 FilterInputStream
一个过滤的InputStream
FilterInputStream(InputStream):使用一个InputStream为参数实例化一个FilterInputStream,其实就是来修饰InputStream的
实现了InputStream中的所有方法1.7.1 BufferedInputStream :使用缓冲区的stream
BufferedInputStream(InputStream):使用InputStream为参数初始化实例
BufferedInputStream(InputStream,int):能够设置缓冲区大小的BufferedInputStream
实现了FilterInputStream中的所有方法(其实也是实现了InputStream中的所有方法)1.7.2 DataInputStream :数字格式化的stream
DataInputStream(InputStream):使用InputStream参数来初始化实例
实现了FilterInputStream中的部分方法
额外的方法:
readInt,readFloat,readDouble…这样可以直接从stream中读取基本类型的数据
2. OutputStream
基类OutputStream
- write(int):写入一个字节到stream中
- write(byte[])写入一个byte数组到stream中
- write(byte[],int,int):把byte数组中从offset开始处写入长度为len的数据
- close():关闭流,这个是在操作完stream之后必须要调用的方法
- flush():这个方法是用来刷新stream中的数据,让缓冲区中的数据强制的输出
1. ByteArrayOutputStream
把信息存入内存中的一个缓冲区中 . 该类实现一个以字节数组形式写入数据的输出流。
当数据写入缓冲区时,它自动扩大。
用 toByteArray() 和 toString() 能检索数据。
2. FileOutputStream
文件输出流是向 File 或 FileDescriptor 输出数据的一个输出流
3. PipedOutputStream
管道输出流是指一个通讯管道的发送端。
一个线程通过管道输出流发送数据,而另一个线程通过管道输入流读取数据,这样可实现两个线程间的通讯。
4. ObjectOutputStream 输出Object对象的stream
5. FilterOutputStream 过滤的OutputStream
BufferedOutputStream :带有缓冲区的stream
DataOutputStream :具有格式化的OutputStream
PrintStream :直接输出到控制台中:我们最熟悉的就是System.out就是一个PrintStream
以字符为导向的 Stream Reader/Writer
以 Unicode 字符为导向的 stream ,表示以 Unicode 字符为单位从 stream 中读取或往 stream 中写入信息。
Reader/Writer 为 abstact 类
Reader:基于字符流的输入stream
InputStream中读取的是byte,而Reader中读取的是char
1. CharArrayReader :与 ByteArrayInputStream 对应此类实现一个可用作字符输入流的字符缓冲区
2. StringReader : 与 StringBufferInputStream 对应其源为一个字符串的字符流
3. FileReader : 与 FileInputStream 对应
4. PipedReader :与 PipedInputStream 对应
5. InputStreamReader : 将InputStream转化成Reader
Writer: 基于字符的输出stream
2.1 CharArrayWriter : 与 ByteArrayOutputStream 对应
2.2 StringWriter :无与之对应的以字节为导向的 stream
2.3 FileWriter : 与 FileOutputStream 对应
2.4 PipedWriter :与 PipedOutputStream 对应
2.5 OutputStreamWriter :将OutputStream转化成Writer
2.6 PrintReader : 和PrintStream对应
InputStreamReader 和 OutputStreamWriter :
把一个以字节为导向的 stream 转换成一个以字符为导向的 stream 。
InputStreamReader 类是从字节流到字符流的桥梁:它读入字节,并根据指定的编码方式,将之转换为字符流。
使用的编码方式可能由名称指定,或平台可接受的缺省编码方式。
InputStreamReader 的 read() 方法之一的每次调用,可能促使从基本字节输入流中读取一个或多个字节。
为了达到更高效率,考虑用 BufferedReader 封装 InputStreamReader ,
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
附,PushbackInputStream, PushbackReader, 回退流,允许放入重读,例如字符乱码处理,语法、词法分析 LineNumberInputStream, LineNumberReader 从流中读取数据时,会得到相应的行号
15. BIO、NIO、AIO区别
BIO | NIO | AIO |
---|---|---|
同步阻塞式IO,使用简单并发能力低 | New IO同步非阻塞式IO,服务器和客户端通过channel通讯,实现多路复用,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理 | NIO.2 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理 |
链接数较少 | NIO方式适用于连接数目多且连接比较短(轻操作)的架构, | AIO方式使用于连接数目多且连接比较长(重操作)的架构 |
聊天服务器,并发局限于应用中,编程比较复杂 | 相册服务器,充分调用OS参与并发操作,编程比较复杂 |
Jdk1.5创造了一个假的nio 用一个HanderExecutorPool来限定了线程数量,无法从根本上解决并发问题
3个NIO相关概念
- Buffer 缓冲区
相比老的IO将数据直接读/写到Stream对象,NIO是将所有数据都用到缓冲区处理,它本质上是一个数组
2.Channel 通道
支持网络数据从Channel中读写,通道写流最大不同是通道是双向的,而流是一个方向上移动(InputStream/OutputStream),通道可用于读/写或读写同时进行,它还可以和下面要讲的selector结合起来,有多种状态位,方便selector去识别. 通道分两类,一:网络读写(selectableChannel),另一类是文件操作(FileChannel)
3.Selector 多路复用选择器
多路复用选择器提供选择已经就绪的任务的能力,也就是selector会不断轮询注册在其上的通道(Channel),如果某个通道发生了读写操作,这个通道处于就绪状态,会被selector轮询出来,然后通过selectionKey可以取得就绪的Channel集合,从而进行后续的IO操作.
一个多路复用器(Selector)可以负责成千上万个Channel,没有上限,这也是JDK使用epoll代替了传统的selector实现,获得连接句柄没有限制.这也意味着我们只要一个线程负责selector的轮询,就可以接入成千上万个客户端,这是JDK,NIO库的巨大进步.
16.Files的常用方法
exists 文件是否存在
createFile 创建文件
createDirectory 创建文件夹
delete 删除文件
copy 复制文件
move 移动文件
size 查看文件个数
read 读取文件
write 写入文件