【十 二】Netty 文件传输

news2025/2/24 12:22:23

概念介绍

文件是最常见的数据源之一,程序经常需要在文件中读取数据,也要将数据保存在文件中,进行持久化。
文件是计算机中一种基本的数据存储形式。即使计算机关机,文件的数据还是存在的,但是内存的数据就会丢失。

相对路径

从当前路径开始: linux 中: …/root/Demo.java。 当前目录的上一级目录中的 root文件夹的Demo.java文件。

绝对路径

从根节点开始,例如:windows 中的 D:\java\nio\netty\Demo.java
linux 中 /root/temp/Demo.java

开发

业务流程图如下:

在这里插入图片描述

FileChannel 介绍

Java NIO 中的FileChannel是一个连接到文件的通道,可以通过这个文件通道读写文件。JDK1.7 之前NIO 的FileChannel是同步阻塞的。JDK1.7对NIO进行了升级,升级后的NIO提供了异步文件通道AsynchronousFileChannel。它支持异步非阻塞文件操作(AIO)。

在使用FileChannel之前必须先打开它,需要有InputStream,OutputSream或者RandomAccessFile来构造FileChannel实例。

RandomAccessFile tempFile=new RandomAccessFile("/home/temp/xxx.java");
FileChannel channel=tempFile.getChannle();

如果要从FileChannel中读取数据,要申请一个ByteBuffer,将数据从FileChannel中读取到字节缓冲中。read()方法返回的Int值表示有多少字节被读到了字节缓冲区中。如果返回-1,表示读到了文件末尾。
反之,如果需要通过FileChannel向文件中写入数据,需要将数据复制或者直接存放到ByteBuffer中,然后调用FileChannel.writer()方法进行写操作。

String content="echo,welcome to File world.";
ByteBuffer wrieteBuffer=ByteBuffer.allocate(128);//缓冲字节分配128 字节大小
//内容放入缓冲字节中
writeBuffer.put(content.getBytes());
writeBuffer.flip();
//将字节内容写入FileChannel 对应的文件中去。
channel.write(buf);

jar 依赖

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId> <!-- Use 'netty5-all' for 5.0-->
            <version>5.0.0.Alpha1</version>
            <scope>compile</scope>
        </dependency>

服务端启动类 FileServer

public class FileServer {
    public void run(int port){
        EventLoopGroup bossGroup=new NioEventLoopGroup();
        EventLoopGroup workGroup=new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap=new ServerBootstrap();
            bootstrap.group(bossGroup,workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,100)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                    .addLast(
                                            //编码  编码器从下至上。 顺序是  FileServerHandler >>>>StringEncoder
                                            //解码 是解码器从上到下。 每一个的返回值是下一个的入参。
                                            //     LineBasedFrameDecoder  >> StringDecoder >>  FileServerHandler
                                            //到 FileServerHandler 拿到的就是String了。

                                            //将文件内容编码为字符串
                                            new StringEncoder(CharsetUtil.UTF_8),
                                            //按照回车换行符对数据报报进行解码
                                            new LineBasedFrameDecoder(1024),
                                            //将数据报解码为字符串
                                            new StringDecoder(CharsetUtil.UTF_8),
                                            //业务处理类
                                            new FileServerHandler());


                        }
                    });
            ChannelFuture future=bootstrap.bind(port).sync();
            System.out.println("Start file server at port : "+port);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new FileServer().run(8080);
    }

}

服务端业务处理类 FileServerHandler

public class FileServerHandler extends SimpleChannelInboundHandler<String> {

    private static final String CR=System.getProperty("line.separator");
    @Override
    protected void messageReceived(ChannelHandlerContext context, String s) throws Exception {
        //通过路径来构造文件
        File file=new File(s);
        //如果文件存在
        if (file.exists()){
            //如果不是文件,是文件夹
            if(!file.isFile()){
                context.writeAndFlush("Not a file : "+file+CR);
                return;
            }
            context.write(file+" "+file.length()+CR);
            //构造只读文件
            RandomAccessFile randomAccessFile=new RandomAccessFile(s,"r");
            //构造netty 的FileRegion对象
            FileRegion region=new DefaultFileRegion(
                    //FileChannel 文件通道,用于对文件进行读写操作
                    randomAccessFile.getChannel(),
                    //0(Position)文件操作的指针位置,读取或写入的起始点。
                    0,
                    //操作的总字节数
                    randomAccessFile.length());

            //实现对文件的发送。由于Netty 底层对文件写入进行了封装,我们不用关心发送的细节。
            context.write(region);
            //写入分割符告诉CMD 控制台,文件传输结束
            context.writeAndFlush(CR);
            randomAccessFile.close();
        }else {
            //文件不存在
            context.writeAndFlush("File not found : "+file+CR);
        }
    }

    public void exceptionCaught(ChannelHandlerContext context,Throwable cause){
        cause.printStackTrace();
        context.close();
    }
}

测试

测试步骤

(1)启动服务端
(2)打开cmd 窗口。输入 telnet 127.0.0.1 8080 (注意ip和端口中间有空格)
(3)连接上了后,复制粘贴文件的绝对路径。 这个输入操作比较麻烦,会有空格等字符串,导致服务器接收的文件路径不正确。所以测试失败了,看下服务器那边接收的路径是否正确。

CMD客户端截图打印

输入的绝对路径是: F:\dubbo_leaning\DoSpring\src\com\echo\service\echo.txt
在这里插入图片描述
文件内容截图如下:
在这里插入图片描述

测试结果说明

通过 这个结果看出。客户端打印了文件名称,说明服务端接收数据正确。
客户端接收了文件内容,说明服务器那边能正确获取文件,并能正确发送。
好了。我们的功能正确的实现 了。没有出现丢包和粘包现象。
如果 CMD客户端输入绝对路径很麻烦。大家可以参考用html 来模拟连接和输入绝对路径。
可以参考这篇博客 https://blog.csdn.net/echohuangshihuxue/article/details/128670385

小伙伴们可以debugger 跟下服务端业务处理类逻辑。能更好的理解本章内容。

总结

本章节介绍了如何利用Netty进行文件传输。由于Netty对文件传输进行了封装,上层应用不需要感知文件操作的细节,Netty提供了多种编码类库,通过组合可以灵活地处理各种文件。
其实 Netty有多种方式实现文件的传输,本章只是实现了比较通用的方式。
比如 Netty 还提供了ChunkedWriteHandler 来解决大文件或者码流传输过程中可能发生的内存溢出问题。总的来说,Netty 的文件传输无论在功能还是可靠性方面,相比较于传统的I/O类库或者其他一些第三方文件传输类库,都有较大的优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/162396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

联合证券|五定增项目同日被否 保荐机构该不该“背锅”?

一天之内5家上市公司定增一起被拒&#xff0c;这一音讯瞬间引发商场重视。 1月11日&#xff0c;浙江世宝、铭普光磁、胜华新材、日辰股份、振华科技等5家上市公司一起公告称&#xff0c;定增不被证监会受理&#xff0c;理由均是证监会以为请求资料不符合法定方式。 投行业界人…

18.Isaac教程--坐标系

坐标系 本节介绍相机、网格/矩阵/图像和机器人坐标系。 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录坐标系网格像素中心网格/矩阵/图像坐标系相机坐标系机器人坐标系网格像素中心 存储网格 GGG 上的值&#xff0c;使得网格单元将值…

Crack:CAD Exchanger GUI/CAD Exchanger Lab 不是SDK

CAD Exchanger GUI/CAD Exchanger Lab 用于查看、转换和分析 CAD、BIM 和 3D 数据 在 Windows、Mac 和 Linux 上加载和转换模型&#xff0c;而无需处理昂贵的 CAD 系统。 使用 CATIA、SOLIDWORKS、Creo、STEP、JT、IFC 和更多格式。 非常适合您的 3D 数据工作流程 连接不同的软…

多频电磁仪在2018年杭州电磁大会的报告(ICEEG)

本篇是对多频电磁方法,应用的解读。 本汇报讲述了EMI传感器的基本情况,以及用手持多频电磁仪进行实际探测应用的例子。 什么是电磁感应?用发射装置(TX)激发谐波,产生一次场(Primary field),地下导体目标会相应产生涡流电磁场,产生二次场,被接收装置(RX)探测到。 …

超参数、划分数据集、偏差与方差、正则化

目录1.超参数(hyperparameters)参数(Parameters)&#xff1a;&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c;...超参数&#xff1a;能够控制参数W,b的参数&#xff0c;是在开始学习之前设置的参数。比如&#xff1a;学习率、梯度下降循环的数量#iterations、隐…

力扣sql基础篇(七)

力扣sql基础篇(七) 1 统计各专业学生人数 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 想要没有学生的部门也保存,就得以部门表作为主表 #字母表顺序就是升序 SELECT d.dept_name,IFNULL(s1.number,0) student_number FROM Department d LEFT …

2022. 12 青少年机器人技术等级考试理论综合试卷(二级)

2022.年12月青少年机器人技术等级考试理论综合试卷&#xff08;二级&#xff09; 一、 单选题(共 30 题&#xff0c; 共 60 分) 1.“机器人三原则” 是由谁提出的&#xff1f; &#xff08; &#xff09; A.美国人艾萨克 阿西莫夫 B.日本人森昌弘 C.美国人乔治 德沃尔 D.中国人…

谈谈 MongoDB 中连接池、索引、事务等问题

大家好&#xff0c;三分钟你将学会&#xff1a; MongoDB连接池的使用方式与常用参数查询五步走&#xff0c;能活九十九&#xff1f;MongoDB索引与MySQL索引有何异同&#xff1f;MongoDB事务与ACID什么是聚合框架&#xff1f;在最开始接触MongoDB的时候&#xff0c;是通过 Mong…

H3C V7MSR路由器定时限速的典型应用配置

某公司希望在上班时间对员工进行每IP限速&#xff0c;其他时间不限制。 1.主要配置如下&#xff1a; #创建关闭接口g0/1的限速功能 scheduler job close-car-g0/1 command 1 system-view command 2 interface g0/1 command 3 undo qos car inbound carl 1 #创建开启接口g0…

什么是CISP-ICSSE?到底该不该考?

CISP-ICSSE注册信息安全专业人员-工业控制系统安全工程师&#xff0c;英文为 Certified Information Security Professional-ICS Security Engineer&#xff0c;简称 CISP-ICSSE。 持证人员可以从事信息安全技术领域工业控制系统安全方向的工作&#xff0c;具备制定工 控安全威…

74. 序列模型

1. 序列数据 实际中很多数据是有时序结构的例如&#xff0c;电影的评价随时间变化而变化 拿奖后评分上升&#xff0c;直到奖项被忘记看了很多好电影后&#xff0c;人们的期望变高季节性&#xff1a;贺岁片、暑期档导演、演员的负面报道导致评分变低 2. 序列数据-更多例子 音…

【文件操作】C语言

目录1. 为什么使用文件2. 什么是文件2.1 程序文件2.2 数据文件2.3 文件名3. 文件的打开和关闭3.1 文件指针3.2 文件的打开和关闭4. 文件的顺序读写5. 文件的随机读写5.1 fseek5.2 ftell5.3 rewind6. 文本文件和二进制文件7. 文件读取结束的判定8. 文件缓冲区1. 为什么使用文件 …

NodeMCU esp8266的网络连入网络的模式方式即程序实例

接入WIFI模式 参考&#xff1a;http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/internet-basics/link-layer/ 模式1 – 无线终端模式&#xff08;Wireless Station&#xff09; 简单说就是把这个开发板做为终端连入WiFi 程序实例 需要注意&#xff1a;端口号…

TikTok的崛起历程:我们所有人都看到了这种潜力

武汉瑞卡迪电子商务有限公司&#xff1a;在短短五年里&#xff0c;TikTok已经爆发成为一种流行文化现象以及一个地缘政治闪爆点。它是全世界最热门的应用&#xff0c;被2/3的美国青少年所使用。它的超级吸引人的短视频格式已经让硅谷争相效仿&#xff0c;并使一夜成名变得比以前…

Linux常用命令——vi命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) vi 功能强大的纯文本编辑器 补充说明 vi命令是UNIX操作系统和类UNIX操作系统中最通用的全屏幕纯文本编辑器。Linux中的vi编辑器叫vim&#xff0c;它是vi的增强版&#xff08;vi Improved&#xff09;&#xff…

SpringBoot启动原理解析

我们开发任何一个 Spring Boot 项目&#xff0c;都会用到如下的启动类 SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args);}}从上面代码可以看出&#xff0c;Annotation 定义&am…

继承是代码复用的最佳方案吗?

继承&#xff0c;一个父类可有许多个子类。父类就是把一些公共代码放进去&#xff0c;之后在实现其他子类时&#xff0c;少写一些代码。 代码复用&#xff0c;很多人觉得继承就是绝佳方案。若把继承理解成代码复用&#xff0c;更多是站在子类角度向上看。在客户端代码使用时&a…

2023云和恩墨生态产品发布会圆满落幕,三款全新产品初亮相,助力千行百业智能升级...

1月12日&#xff0c;以“多元共生&#xff0c;智创未来”为主题的2023云和恩墨生态产品发布会在线上成功召开&#xff0c;发布了三款全新产品&#xff1a;zData X 数据库一体机、zCloud for DBaaS平台和 zAIoT 机器数据智管产品。本次发布会还得到了来自中国信通院云大所、科大…

记一个奇怪的gcc编译优化:-ftree-vrp

记一个奇怪的gcc编译优化&#xff1a;-ftree-vrp最近有同事遇到一个gcc不同编译优化选项结果不一致的问题&#xff0c;从该问题反映出编程规范&#xff08;我更倾向于华为内部使用的”编程军规“的叫法&#xff09;的问题非常有参考意义&#xff0c;在此分享给大家。 程序可简…

通信原理与MATLAB(十四):HDB3的编解码

目录1.HDB3码的编码原理2.HDB3码的解码原理3.HDB3码的编解码的代码4.HDB3码的误码率曲线4.1原理4.2 HDB3码的误码率曲线的代码4.3 HDB3码的误码率曲线图1.HDB3码的编码原理 如下图所示&#xff0c;HDB3编码的步骤&#xff1a; (1)原码中连0的个数小于等于3&#xff0c;则和AMI…