• Netty学习(3):文件操作


    概述

    在 Netty学习(2)中,我们先浅浅认识了 NIO 的3大核心组件,现在就让我们针对其深入学习,通过一些简单的文件操作来深入理解其中的 BufferChannel 的概念。

    文件写入

    将内存中的数据写入到文件中,如果文件不存在,那么就新建文件。

    // 数据 -> 文件
        private static void dataToFile(String data, String filePath) {
            // 构建输出流  ->   从输出流中获取 channel
            try (FileOutputStream fileOutputStream = new FileOutputStream(filePath);
                 FileChannel fileChannel = fileOutputStream.getChannel()) {
    
                // 设置缓冲区
                ByteBuffer byteBuffer = ByteBuffer.allocate(BYTE_BUFFER_LENGTH);
    
                // 将需要读写的数据放到缓冲区
                int i = 0;
                int length = data.getBytes().length;
                // 一次就可以读完
                if (BYTE_BUFFER_LENGTH > data.getBytes().length) {
                    byteBuffer.put(data.getBytes(), i, data.getBytes().length);
                    byteBuffer.flip();
                    fileChannel.write(byteBuffer);
                } else {
                    // 一次读不完  需要循环读取
                    for (int temp = 0; temp < data.getBytes().length; temp += BYTE_BUFFER_LENGTH) {
                        byteBuffer.clear();
                        byteBuffer.put(data.getBytes(), temp, BYTE_BUFFER_LENGTH);
                        // 翻转缓冲区,可以对外读
                        // 这里的 flip() 是重点,其可以将Buffer的属性重置,可以对外写
                        byteBuffer.flip();
                        // 将缓冲区内的数据写到 channel中
                        fileChannel.write(byteBuffer);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    这样,我们就写完了一个文件写入的函数,在需要时传入指定的字符串即可。

    文件读取

    从文件中读取数据,并将其输出到控制台中。

     // 文件 -> 内存
        private static void dataFromFile(String filePath) {
            File file = new File(filePath);
            // 从输入流中获取 channel
            try (FileInputStream fileInputStream = new FileInputStream(file);
                 FileChannel channel = fileInputStream.getChannel()) {
    
                // 分配缓冲区
                ByteBuffer byteBuffer = ByteBuffer.allocate(BYTE_BUFFER_LENGTH);
                StringBuilder result = new StringBuilder();
                while (true) {
                    byteBuffer.clear();
                    // 将 channel数据写到buffer中
                    int read = channel.read(byteBuffer);
                    // 因为byteBuffer大小原因,因此需要用一个中间字符串接受一下
                    result.append(new String(byteBuffer.array()));
                    if (read == -1) {
                        break;
                    }
                }
    
                logger.info("从文本读取结果:{}", result);
            } catch (Exception e) {
                logger.error("文件读取错误,错误原因 :{}", e);
            }
        }
    

    文件拷贝

    用 NIO 来完成文件拷贝,有两种实现方式,一种是用 Buffer 完成两个文件之间数据的转移,另一种是直接使用 Channel 来完成文件复制。

    Buffer 完成

    通过 Buffer 来完成文件复制,步骤如下:

    1. 获取源文件(source)和目标文件(target)的 channel;
    2. 设置缓冲区;
    3. 在循环中,通过缓冲区,将 source 的数据写入到 target 的 channel 中,完成写入,即复制成功。
    // 将两个channel通过byteBuffer进行转移
        private static void copyFileUseBuffer(String sourceFilePath, String targetFilePath) {
            File source = new File(sourceFilePath);
            File target = new File(targetFilePath);
            // 获取文件输入输出流
            // 从输入输出流中获取输入输出 channel
    
            try (FileInputStream fileInputStream = new FileInputStream(source);
                 FileOutputStream fileOutputStream = new FileOutputStream(target);
                 FileChannel fileInputStreamChannel = fileInputStream.getChannel();
                 FileChannel fileOutputStreamChannel = fileOutputStream.getChannel()) {
    
                // 分配缓冲区
                ByteBuffer byteBuffer = ByteBuffer.allocate(BYTE_BUFFER_LENGTH);
                // 将输入流中的数据写到缓冲区
                // 这里需要循环读取,如果是大文件,不能直接建立一个很大的内存空间,直接全部放进去,并且还可能放不进去
                while (true) {
                    byteBuffer.clear();
    
                    int read = fileInputStreamChannel.read(byteBuffer);
                    if (read == -1) {
                        break;
                    }
                    // 翻转缓冲区
                    byteBuffer.flip();
    
                    // 将翻转后可以对外写的缓存区的内容写到输出流,从而形成文件
                    fileOutputStreamChannel.write(byteBuffer);
                }
            } catch (Exception e) {
                logger.error("文件复制错误,错误原因 :{0}", e);
            }
       
    

    Channel 完成

    但其实,Java 官方也考虑到这个需求,其内置了一个通道复制的函数,可以直接完成复制。

    // 直接用channel的复制完成文件复制
        private static void copyFileUseChannelTransfer(String sourceFilePath, String targetFilePath) {
            File source = new File(sourceFilePath);
            File target = new File(targetFilePath);
            // 获取文件输入输出流
            // 从输入输出流中获取输入输出 channel
            try (FileInputStream fileInputStream = new FileInputStream(source);
                 FileOutputStream fileOutputStream = new FileOutputStream(target);
                 FileChannel fileInputStreamChannel = fileInputStream.getChannel();
                 FileChannel fileOutputStreamChannel = fileOutputStream.getChannel()) {
    
                // 直接将输入channel复制到输出channel
                fileOutputStreamChannel.transferFrom(fileInputStreamChannel, fileInputStreamChannel.position(), fileInputStreamChannel.size());
    
            } catch (Exception e) {
                logger.error("文件复制错误,错误原因 :{0}", e);
            }
        }
    

    总结

    本文,我们通过文件的读取,写入,复制,从而理解了 Buffer 和 Channel 的作用和使用方式,在后续的网络编程中,我们还要用到这些操作方式,以便逐步深入到 Netty 的学习范围。

    本文中代码已上传到 GitHub 上,地址为 https://github.com/wb1069003157/nettyPre-research ,欢迎大家来讨论,探讨。

    iceWang公众号

    文章在公众号「iceWang」第一手更新,有兴趣的朋友可以关注公众号,第一时间看到笔者分享的各项知识点,谢谢!笔芯!

  • 相关阅读:
    JQuery Table 合并单元格-解决Bug版本
    SQLServer当数据导入平面文件
    【BZOJ1294】[SCOI2009]围豆豆Bean 射线法+状压DP+SPFA
    【BZOJ3590】[Snoi2013]Quare 状压DP
    【BZOJ4036】[HAOI2015]按位或 FWT
    【BZOJ1502】[NOI2005]月下柠檬树 Simpson积分
    【CF603E】Pastoral Oddities cdq分治+并查集
    【CF891E】Lust 生成函数
    【CF618G】Combining Slimes 概率+矩阵乘法
    【CF633H】Fibonacci-ish II 莫队+线段树
  • 原文地址:https://www.cnblogs.com/JRookie/p/12394482.html
Copyright © 2020-2023  润新知