NIO之Channel详解

NIO介绍

  在讲解Channel之前,首先了解一下NIO, Java NIO全称java non-blocking IO,是从Java 1.4版本开始引入的一个新的IO API(New IO),可以替代标准的Java IO API,NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同。IO与 NIO区别:

IONIO
面向流(Stream Orientend)面向缓冲区(Buffer Orientend)
阻塞IO(Blocking IO )非阻塞IO(Non Blocking IO)
选择器(Selector)

  NIO支持面向缓冲区的、基于通道的IO操作并以更加高效的方式进行文件的读写操作,其核心API为Channel(通道),Buffer(缓冲区), Selector(选择器)。Channel负责传输,Buffer负责存储 。

通道(Channel )

  通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。
  Channel相比IO中的Stream更加高效,可以异步双向传输,但是必须和buffer一起使用。

主要实现类

FileChannel,读写文件中的数据。
SocketChannel,通过TCP读写网络中的数据。
ServerSockectChannel,监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
DatagramChannel,通过UDP读写网络中的数据。

他们的使用方法会在代码中体现出来。

主要获取方式

  1、java针对支持通道的类提供了getChannel()方法

本地io:
   FileInputStreanm/FileOutputStream
  RandomAccessFile
网络io:
  Socket
  ServerSocket
  DatagramSocket

        FileInputStream fis = new FileInputStream("D:\\1.jpg");
        FileChannel inChannel = fis.getChannel();

   2、 jdk1.7的nio2只对各个通道提供了一个静态方法open()

        FileChannel inChannel = FileChannel.open(Paths.get("D:\\1.jpg"), StandardOpenOption.READ);

通道之间的数据传输

  1、read&write

//将 Buffer 中数据写入 Channel
outChannel.write(buff)
//从 Channel 读取数据到 Buffer
inChannel.read(buff)

  2、transferFrom

从源信道读取字节到这个通道的文件中。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。这种方法可能比从源通道读取并写入此通道的简单循环更有效率。
@param SRC 源通道
@param position 调动开始的文件内的位置,必须是非负的
@param count 要传输的最大字节数,必须是非负
@return 传输文件的大小(单位字节),可能为零,
public abstract long transferFrom(ReadableByteChannel src, long position, long count) throws IOException;

    //复制图片,利用直接缓存区
    public void test() throws Exception{
        FileChannel inChannel = FileChannel.open(Paths.get("D:\\1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("D:\\2.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        outChannel.transferFrom(inChannel,0, inChannel.size()); 
        inChannel.close();
        outChannel.close();
    }

 3、transferTo

将字节从这个通道的文件传输到给定的可写字节通道。
@param position 调动开始的文件内的位置,必须是非负的
@param count 要传输的最大字节数,必须是非负
@param target 目标通道
@return 传输文件的大小(单位字节),可能为零,
public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException;

     //复制图片,利用直接缓存区
    public void test2() throws Exception{
        FileChannel inChannel = FileChannel.open(Paths.get("D:\\1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("D:\\3.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        inChannel.transferTo(0, inChannel.size(), outChannel);  
        inChannel.close();
        outChannel.close();
    }
    }

常用方法

方 法描 述
int read(ByteBuffer dst)从Channel到中读取数据到ByteBuffer
long read(ByteBuffer[] dsts)将Channel到中的数据“分散”到ByteBuffer[]
int write(ByteBuffer src)将ByteBuffer到中的数据写入到Channel
long write(ByteBuffer[] srcs)将ByteBuffer[]到中的数据“聚集”到Channel
long position()返回此通道的文件位置
FileChannel position(long p)设置此通道的文件位置
long size()返回此通道的文件的当前大小
FileChannel truncate(long s)将此通道的文件截取为给定大小
void force(boolean metaData)强制将所有对此通道的文件更新写入到存储设备中

示例代码

     //利用通道完成文件的复制,非直接缓冲区
    @Test
    public void test() throws Exception{
        FileInputStream fis = new FileInputStream("D:\\1.jpg");
        FileOutputStream fos = new FileOutputStream("D:\\2.jpg");
        //获取通道
        FileChannel inChannel = fis.getChannel();
        FileChannel outChannel = fos.getChannel();
        //分配指定大小缓存区
        ByteBuffer buff = ByteBuffer.allocate(1024);// position 0 ,limit 1024
        //将通道的数据存入缓存区
        while(inChannel.read(buff)!=-1){// position 1024 ,limit 1024 ,相当于put
            //切换读模式
            buff.flip();//position 0 ,limit 1024
            //将缓存去的数据写入通道
            outChannel.write(buff);//position 1024 ,limit 1024,相当于get
            //清空缓冲区
            buff.clear();//position 0 ,limit 1024
        }
        outChannel.close();
        inChannel.close();
        fis.close();
        fos.close();
    }

    //利用通道完成文件的复制,直接缓冲区,利用物理内存映射文件
    //会出现文件复制完了,但程序还没结束,原因是JVM资源还在用,当垃圾回收机制回收之后程序就会结束,不稳定
    @Test
    public void test1() throws Exception{
        FileChannel inChannel = FileChannel.open(Paths.get("D:\\1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("D:\\4.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        //内存映射文件
        MappedByteBuffer inMapBuff = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());//==allocateDirect
        MappedByteBuffer outMapBuff = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
        byte[] by = new byte[inMapBuff.limit()];
        inMapBuff.get(by);
        outMapBuff.put(by);
        outChannel.close();
        inChannel.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值