【NIO总结】—NIO中的通道

        通道是由java.nio.channels包定义的,表示IO源与目标打开的连接。Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,只能与Buffer进行交互。

 

        通道是java.nio全新的东西,不是扩展也不是增强。通道可以理解为管道,比如要将一个大桶中的水排出,可以在桶壁上插上一个管道,使得水从管道中流出来,水就可以看成是数据。

 

 

通道的类型

 

 

 

        FileChannel:用于读取、写入、映射和操作本地文件的通道

        DatagramChannel:通过UDP读写网络中的数据通道

        SocketChannel:通过TCP读写网络中的数据

 

        ServerSocketChannel:可以监听新进来的TCP连接,对每一个新进来的连接都会创建一个SocketChannel

 

 

获取通道的方式:

 

        一是对支持通道的对象调用getChannel()方法。

                支持通道的类:

                        本地IO:FileInputStream、FileOutputStream、RandomAccessFile

                        网络IO:DatagramSocket、Socket、ServerSocket

 

        二是在JDK1.7中的NIO.2针对各个通道提供了静态方法open()

 

 

        三是在JDK1.7中的NIO.2的Files工具类的newByteChannel()方法

 

 

测试Channel

 

        下面的代码是利用Channel来复制文件,首先采用的是非直接缓冲区方式,非直接缓冲区操作起来比较慢,它是直接通过普通的方式获取缓冲区,默认是非直接缓冲区:

 

 

inputStream = new FileInputStream("d:/1.iso");
outputStream = new FileOutputStream("d:/2.iso");
channel1 = inputStream.getChannel();
channel2 = outputStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(channel1.read(buffer) != -1){
    buffer.flip();
    channel2.write(buffer);
    buffer.clear();
}

 

 

        下面的代码是采用直接缓冲区的方式来进行,直接缓冲区可以使用Channel的map方法来创建,这里面的Channel是采取open方法来创建的:

 

 

channel1 = FileChannel.open(Paths.get("d:/1.mp3"), StandardOpenOption.READ);
channel2 = FileChannel.open(Paths.get("d:/2.mp3"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
buffer1 =  channel1.map(FileChannel.MapMode.READ_ONLY,0,channel1.size());
buffer2 = channel2.map(FileChannel.MapMode.READ_WRITE,0,channel1.size());
byte[] bytes = new byte[buffer1.limit()];
buffer1.get(bytes);
buffer2.put(bytes);

 

 

        open方法创建Channel时,可以设置是创建什么类型的通道,StandardOpenOption类定义的是打开类型,可以是READ,WRITE等等各种类型。同样的,在使用map方法创建缓冲区时也需要设定模式,例如对应channel1,创建buffer1就可以使用只读READ_ONLY模式;但是对于channel2,因为是通过channel2写入2.mp3,所以既可读又可写,所以在创建缓冲区的时候需要使用读写READ_WRITE模式。

 

通道和缓冲区数据传输

 

 

数据是从Buffer中写入Channel

 

int bytes = channel.write(buffer);

 

数据是从Channel中读取到Buffer中的

 

int bytes = channel.write(buffer);

 

 

通道和通道之间的数据传输

 

 

transferFrom():该方法是从数据源通道将数据传输到目的通道,参数是源通道和源通道大小

 

channel2.transferFrom(channel1,0,channel1.size());//channel2为目的通道,channel1为源通道

 

 

transferTo():发方法是从数据源通道将数据传输到目的通道,参数是源通道大小和目的通道

 

channel1.transferTo(0,channel1.size(),channel2);//channel1为源通道,channel2为目的通道

 

 

分散读取和聚集写入

 

        分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中。分散读取时,需要按照Buffer的顺序,从Channel中读取数据依次将Buffer填满。

 

                                                                   

 

 

        聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中。聚集写入时,需要按照Buffer的顺序,写入position和limit之间的数据到Channel。

 

                                                                          

 

@Test
//测试分散读取和聚集写入
public void testScatterAndGather(){
    RandomAccessFile file = null;
    RandomAccessFile file2 = null;
    try {
        file = new RandomAccessFile("d:/1.txt","rw");
        FileChannel channel = file.getChannel();
        ByteBuffer buffer1 = ByteBuffer.allocate(20);
        ByteBuffer buffer2 = ByteBuffer.allocate(50);

        ByteBuffer[] buffers = {buffer1,buffer2};
        channel.read(buffers);

        for(ByteBuffer byteBuffer : buffers){
            byteBuffer.flip();
        }

        System.out.println(new String(buffers[0].array(), 0, buffers[0].limit()));
        System.out.println("\n");
        System.out.println(new String(buffers[1].array(), 0, buffers[1].limit()));

        file2 = new RandomAccessFile("d:/2.txt","rw");
        FileChannel channel1 = file2.getChannel();
        channel1.write(buffers);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }catch (IOException e){
        e.printStackTrace();
    }finally {
        try {
            file.close();
            file2.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值