NIO学习之Channel通道(与缓冲区组合实现文件的复制和转移)

引言

    前面我们学习了NIO中的缓冲区,了解了相应的功能和相关的实现方法详见(NIO学习之简介+Buffer部分源码阅读分析记录1)。本篇博文我们主要记录一下通道的一些基础概念,并且使用通道+缓冲区实现文件的复制和转移。

Channel简介

    在前一篇文章中,我们通过JDK1.8的官网了解到了 Channe的接口在java.nio.channel包下面,表示IO源与目标打开的连接,主要与缓冲区进行交互。
在这里插入图片描述
在这里插入图片描述

Channel接口已知的实现类

在这里插入图片描述
    其中主要的实现类如下:

类名功能
FileChannel用于读取,写入,映射和操作文件的通道
DatagramChannel通过UDP读写网络中的数据通道
SocketChannel通过TCP读写网络中的数据通道
ServerSocketChannel可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。

获取通道的方法

在这里插入图片描述

通道中数据的传输

在这里插入图片描述

相关代码实现

通过文件输入出流获取通道使用非直接缓冲区实现文件的复制

  1. 目录结构
    在这里插入图片描述
  2. 实现代码
@Test
    public void test1() {
        long start = System.currentTimeMillis();
        //首先动态的获取到要复制的文件的路径
        String path = TestChannel.class.getResource("/")
                .getPath().substring(1)
                .replace("target/classes/", "src/main/resources");
        //定义文件输入流
        FileInputStream fileInputStream = null;
        //定义文件输出流
        FileOutputStream fileOutputStream = null;
        //定义通道
        FileChannel inFileChannel = null;
        FileChannel outFileChannel = null;
        try {
            //获取文件流
            fileInputStream = new FileInputStream(path + "/text.txt");
            fileOutputStream = new FileOutputStream(path + "/text1.txt");
            //获取通道
            inFileChannel = fileInputStream.getChannel();
            outFileChannel = fileOutputStream.getChannel();

            //指定缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            while (inFileChannel.read(byteBuffer) != -1) {
                byteBuffer.flip(); //切换读取数据的模式
                //④将缓冲区中的数据写入通道中
                outFileChannel.write(byteBuffer);
                byteBuffer.clear(); //清空缓冲区
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流和通道
            if (outFileChannel != null) {
                try {
                    outFileChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inFileChannel != null) {
                try {
                    inFileChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("耗费时间为:" + (end - start));
    }
  1. 运行结果
    在这里插入图片描述

使用直接缓冲区完成文件的复制(内存映射文件)

  1. 实现代码
 //使用直接缓冲区完成文件的复制(内存映射文件)
    @Test
    public void test2() throws IOException {
        long startTime = System.currentTimeMillis();
        //首先动态的获取到要复制的文件的路径
        String path = TestChannel.class.getResource("/")
                .getPath().substring(1)
                .replace("target/classes/", "src/main/resources");
        //获取通道
        FileChannel inChannel = FileChannel.open(Paths.get(path + "/text.txt"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get(path + "/text2.txt"), StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);

        //定义缓冲区
        MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
        MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());

        //直接对缓冲区进行数据的读写操作
        byte[] dst = new byte[inMappedBuf.limit()];
        inMappedBuf.get(dst);
        outMappedBuf.put(dst);

        inChannel.close();
        outChannel.close();

        long endTime = System.currentTimeMillis();
        System.out.println("复制时间为:" + (endTime - startTime));
    }
  1. 运行结果
    在这里插入图片描述

使用通道间的文件传输实现文件复制

  1. 实现代码
   long startTime = System.currentTimeMillis();
        //首先动态的获取到要复制的文件的路径
        String path = TestChannel.class.getResource("/")
                .getPath().substring(1)
                .replace("target/classes/", "src/main/resources");
        //获取通道
        FileChannel inChannel = FileChannel.open(Paths.get(path + "/text.txt"), StandardOpenOption.READ);
        FileChannel outChannel1 = FileChannel.open(Paths.get(path + "/text3.txt"), StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        FileChannel outChannel2 = FileChannel.open(Paths.get(path + "/text4.txt"), StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        inChannel.transferTo(0,inChannel.size(),outChannel1);
        outChannel2.transferFrom(inChannel,0,inChannel.size());
        long endTime = System.currentTimeMillis();
        System.out.println("复制时间为:" + (endTime - startTime));
  1. 运行结果
    在这里插入图片描述

使用分散和聚集实现文件的复制

  1. 实现代码
  //分散和聚集
	@Test
	public void test4() throws IOException{
		RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw");

		//1. 获取通道
		FileChannel channel1 = raf1.getChannel();

		//2. 分配指定大小的缓冲区
		ByteBuffer buf1 = ByteBuffer.allocate(100);
		ByteBuffer buf2 = ByteBuffer.allocate(1024);

		//3. 分散读取
		ByteBuffer[] bufs = {buf1, buf2};
		channel1.read(bufs);

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

		System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
		System.out.println("-----------------");
		System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));

		//4. 聚集写入
		RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw");
		FileChannel channel2 = raf2.getChannel();

		channel2.write(bufs);
	}

  1. 运行结果
    在这里插入图片描述

参考链接

Java NIO学习篇之通道Channel详解
JDK1.8API

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值