java nio学习之Channel(三)

实战

复制一张图片

public static void main(String[] args) throws IOException {
        String fileName = parentPath + "\\104.jpg";
        Pipe pipe = Pipe.open();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        try (WritableByteChannel writableByteChannel = Channels.newChannel(Channels.newOutputStream(pipe.sink()))){
            FileChannel channel = new FileInputStream(fileName).getChannel();
            channel.transferTo(0, new File(fileName).length(), writableByteChannel);
        }

        File file = new File(parentPath + "\\b.jpg");
        ReadableByteChannel readableByteChannel = pipe.source();
        FileChannel fileChannel = new FileOutputStream(file).getChannel();

        while (readableByteChannel.read(byteBuffer) > 0) {
            byteBuffer.flip();
            fileChannel.write(byteBuffer);
            byteBuffer.clear();
        }

    }

    private static String parentPath = "D:\\github\\zip";
    private static String path = parentPath + "\\104.jpg";

上面这样写是因为想熟悉一下NIO,Java NIO管道是2个线程之间的单向数据连接。Pipe有一个源通道和一个sink通道.

sink负责写通道,source负责读通道

为啥这么做

查看这一篇https://mp.weixin.qq.com/s?__biz=MzIwMDY0Nzk2Mw==&mid=2650320600&idx=1&sn=31b01b7887f1880510549ac28efe738a&chksm=8ef5faacb98273bad0de9b1ed1a94bc894cdd330e911d10828281c67f734b1548a39bd07fa70&mpshare=1&scene=2&srcid=&sharer_sharetime=1567731655097&sharer_shareid=2a6de52c25a6a3a0164993bffe122d8a&from=timeline&clicktime=1567731954#rd

transferTo

首先是transferTo,

我们可以看到这里并没有使用ByteBuffer进行数据传输,而是使用了transferTo的方法。这个方法是将两个通道进行直连。

This method is potentially much more efficient than a simple loop* that reads from this channel and writes to the target channel.  Many* operating systems can transfer bytes directly from the filesystem cache* to the target channel without actually copying them. 

这是源码上的描述文字,大概意思就是使用transferTo的效率比循环一个Channel读取出来然后再循环写入另一个Channel好。操作系统能够直接传输字节从文件系统缓存到目标的Channel中,而不需要实际的copy阶段。

copy阶段就是从内核空间转到用户空间的一个过程

缓冲器介绍

我们可以看到一半的copy是从内核空间复制到用户空间,而transferTo就是开辟直接缓存。还可以开辟一个物理内存映射,MappedByteBuffer。

sink和source相互阻塞

Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。其中source通道用于读取数据,sink通道用于写入数据。可以看到源码中的介绍,大概意思就是写入线程会阻塞至有读线程从通道中读取数据。如果没有数据可读,读线程也会阻塞至写线程写入数据。直至通道关闭。

 Whether or not a thread writing bytes to a pipe will block until another thread reads those bytes

我们可以使用CompletableFuture将sink和source进行异步分开操作。

原理

点这里

单纯的复制

WritableByteChannel writableByteChannel = Channels.newChannel(zipOut);
        try (FileChannel fileChannel = new FileInputStream(fileToZip).getChannel()) {
            fileChannel.transferTo(0, fileToZip.length(), writableByteChannel);
        }

很简单就实现了。

发布了213 篇原创文章 · 获赞 31 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/weixin_38336658/article/details/100630495