NIO

JAVA NIO:称为非阻塞IO,读写的过程中不会发生阻塞线程
我们之前所学习的流,称为BIO,阻塞是IO,就是在读写的过程中可能会发生阻塞现象。

非阻塞IO面向Channel("通道")的,不是面向Stream(流)的。

流的特点:方向单一,顺序读写。流要么是输入流用于顺序读取数据,要么是输出流用于顺序写出数据

Channel的特点:双向的,既可以读又可以写。

JAVA NIO核心API:Channel 通道

常见的实现:
FileChannel:文件通道,可对文件进行读写操作
SocketChannel:套接字通道,可以与远端计算机进行TCP读写操作
ServerSocketChannel:服务端的套接字通道,用于监听客户端的连接

Buffer缓冲区

通道是对缓冲区中的数据进行读写操作
常见的缓冲区实现
ByteBuffer:字节缓冲区,缓冲区内部内容都是字节


//ByteBuffer支持一个静态方法,不用new:字节数组缓冲区,下面还有个buffer,不常用


缓冲区中重要的几个属性: position:当前位置,用来表示当前缓冲区已经有多少数据被操作了 limit:缓冲区最大可以操作的位置 capacity:容量,缓冲区的大小 默认创建一个缓冲区时: position=0 limit=capacity capacity=创建缓冲区时指定的大小

缓冲区的方法:

public abstract class Buffer {
     public final Buffer flip() {
     limit = position;
     position = 0;
     mark = -1;
     return this;
    }
     public final Buffer clear() {
     position = 0;
     limit = capacity;
     mark = -1;
     return this;
    }
}

缓冲区内部读写过程:

FileInputStream fis = new FileInputStream("movie.wmv");
FileChannel inChannel = fis.getChannel();//读取通道
//基于文件输入流获取一个用于读取该文件的文件通道

FileOutputStream fos = new FileOutputStream("movie_cp2.wmv");
FileChannel outChannel = fos.getChannel();//写出通道
//获取的输入流与输出流名字一样,因为这个通道同时有读取和写出的功能

//创建一个字节缓冲区
ByteBuffer buffer = ByteBuffer.allocate(14);//创建一个14字节大小的缓冲区
int len;//记录每次实际读取的数据量
/*
初始值:
  position=0
  limit=14
  一次可以读取最多读取数据为:position到limit之间的数据量
  limit-position = 14
*/

//实例1:只进行读取操作
       //假设要读取的文件(movie.wmv)的大小为14字节
       //读取前
       System.out.println("读取前buffer状态=========================");
       System.out.println("position:"+buffer.position());//0
       System.out.println("limit:"+buffer.limit());//14

       //第一次读取:
       len = inChannel.read(buffer);//从通道中读取数据到缓冲区中
       System.out.println("本次读取了:"+len+"个字节");//14
       System.out.println("读取后buffer状态=========================");
       System.out.println("position:"+buffer.position());//14
       System.out.println("limit:"+buffer.limit());//14

       //第二次读取
       len = inChannel.read(buffer);
       System.out.println("本次读取了:"+len+"个字节");//0
       System.out.println("读取后buffer状态=========================");
       System.out.println("position:"+buffer.position());//14
       System.out.println("limit:"+buffer.limit());//14
     /*
       position=14
       limit=14
       一次可以读取最多读取数据为:position到limit之间的数据量
       limit-position = 0
       由于position的位置与limit一致,因此表示目前缓冲区已经没有空余可操作的空间了
     */

//实例2:复制操作(先读取后写出)
       //假设要读取的文件(movie.wmv)的大小为16字节
       //读取前
       System.out.println("读取前buffer状态=========================");
       System.out.println("position:"+buffer.position());//0
       System.out.println("limit:"+buffer.limit());//14

       len = inChannel.read(buffer);//第一次读取
       //读取后:position:14,limit:14
       outChannel.write(buffer);//此时写出字节个数为:0
       //读取与写出操作都会影响到position的位置
       //第一次读取后再写出发现写出字节数为0
       //此时应用Buffer类的flip()和clear()方法

//实例3:复制文件:调用flip和clear方法,读取文件大小:16字节
       len = inChannel.read(buffer);
       //第一次读取了14个字节                               position:14; limit:14
       Buffer.flip();
       //filp后,将position赋给limit,position=0           position:0; limit:14
       outChannel.write(buffer);
       //此时写出字节个数为:14                             position:14; limit:14
       Buffer.clear();
       //clear后,limit=buffer最大容量,position=0           position:0; limit:14
       
       len = inChannel.read(buffer);
       //第二次读取了2个字节                                position:2; limit:14
       Buffer.flip();
       //filp后,将position赋给limit,position=0           position:0; limit:2
       outChannel.write(buffer);
       //此时写出字节个数为:2                              position:2; limit:2
       Buffer.clear();
       //clear后,limit=buffer最大容量,position=0           position:0; limit:14

总结:
Channel通道在进行读或写操作时,具体可以读取多少个字节或写出多少个字节是取决于
我们传入的Buffer中position到limit之间的空间。

文件复制

BIO文件复制

/*
*BIO的文件复制操作,使用流的方式进行复制
*/
FileInputStream fis = new FileInputStream("movie.wmv");
FileOutputStream fos = new FileOutputStream("movie_cp.wmv");
byte[] buffer = new byte[1024*10];//创建一个字节数组作为缓冲区
int len;//记录每次实际读取的字节数
while((len = fis.read(buffer))!=-1){
      fos.write(buffer,0,len);
     }
System.out.println("复制完毕");
fis.close();
fos.close();

NIO文件复制

/*
*NIO的文件复制操作
*/
FileInputStream fis = new FileInputStream("movie.wmv");
FileChannel inChannel = fis.getChannel();

FileOutputStream fos = new FileOutputStream("movie_cp2.wmv");
FileChannel outChannel = fos.getChannel();//同上

//创建一个字节缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024*10);//创建一个10k大小缓冲区
int len;//记录每次实际读取的数据量
//完整的复制动作
while((len = inChannel.read(buffer))!=-1){
      buffer.flip();
      outChannel.write(buffer);
      buffer.clear();
}

 过程分析:

java 输出单通道灰度值 java通道和流_开发语言