视频断点上传

什么是断点续传

通常视频文件都比较大,所以对于媒资系统上传文件的需求要满足大文件的上传要求。http协议本身对上传文件大小没有限制,但是客户的网络环境质量、电脑硬件环境等参差不齐,如果一个大文件快上传完了网断了没有上传完成,需要客户重新上传,用户体验非常差,所以对于大文件上传的要求最基本的是断点续传。

什么是断点续传:

        引用百度百科:断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载,断点续传可以提高节省操作时间,提高用户体验性。

断点续传流程如下图:

流程如下:

1、前端上传前先把文件分成块

2、一块一块的上传,上传中断后重新上传,已上传的分块则不用再上传

3、各分块上传完成最后在服务端合并文件

 文件分块

文件分块的流程如下:

1、获取源文件长度

2、根据设定的分块文件的大小计算出块数

3、从源文件读数据依次向每一个块文件写数据。

/*** 文件分块上传测试*/@Testpublic  void  testChunk(){//获取源文件File sourceFile = new File("B:\\workspace\\test\\you.ncm");//源文件字节大小long length = sourceFile.length();//分块文件目录String chunkPath="B:\\workspace\\test\\chunk\\";File chunkFolder = new File(chunkPath);//检查目录是否存在if (!chunkFolder.exists()) {//不存在就创建chunkFolder.mkdirs();}//分块大小long chunkSize = 1024*1024*1;//分块数量long chunkNum = (long) Math.ceil(length * 1.0 / chunkSize);//缓冲区大小byte[] b = new byte[1024];//使用RandomAccessFile访问文件try {RandomAccessFile read = new RandomAccessFile(sourceFile, "r");for (int i = 0; i < chunkNum; i++) {//创建分块文件File file = new File(chunkPath + i);//检查文件是否存在,如果存在就删除文件if(file.exists()){file.delete();}//创建一个新文件boolean newFile = file.createNewFile();if (newFile){//向分块文件中写数据RandomAccessFile write = new RandomAccessFile(file,"rw");int len = -1;while ((len = read.read(b)) != -1) {write.write(b, 0, len);//如果分块文件的大小大于等于分块大小就跳过本次循环if (file.length() >= chunkSize) {break;}}write.close();System.out.println("完成分块"+i);}}read.close();} catch (Exception e) {e.printStackTrace();}}

RandomAccessFile 是 Java 中的一个类,它允许对文件的任意位置进行读写操作。与其他的输入/输出流(如 InputStream 和 OutputStream)不同,RandomAccessFile 并不属于它们的类系,而是直接继承自 Object 类。它提供了类似于文件系统中的随机访问功能,因此得名“随机访问文件”。

以下是 RandomAccessFile 的一些主要特点和功能:

  1. 随机访问RandomAccessFile 允许你直接跳到文件的任意位置来读写数据。这是通过使用 seek(long pos) 方法实现的,它可以将文件的指针移动到指定的位置。
  2. 读写功能RandomAccessFile 既可以从文件中读取数据,也可以向文件中写入数据。它提供了类似于 InputStream 的 read() 方法和类似于 OutputStream 的 write() 方法来执行这些操作。
  3. 文件指针操作:除了 seek(long pos) 方法外,RandomAccessFile 还提供了 getFilePointer() 方法来返回文件记录指针的当前位置。
  4. 访问模式:在创建 RandomAccessFile 对象时,你需要指定一个访问模式,它决定了文件是以只读方式打开还是以读写方式打开。常见的访问模式有 "r"(只读)和 "rw"(读写)。
  5. 文件操作模式:在 JDK 1.6 及更高版本中,RandomAccessFile 还支持 "rws" 和 "rwd" 模式。在 "rws" 模式下,每次写入操作都会确保数据被写入到磁盘中;而在 "rwd" 模式下,只有在对文件执行了某些特定的更新操作(如关闭文件或调用 flush() 方法)后,数据才会被写入到磁盘中。
  6. 内存映射文件:虽然 RandomAccessFile 提供了强大的文件访问功能,但在某些情况下,使用 JDK 1.4 引入的“内存映射文件”可能会更高效。内存映射文件允许你将文件的一部分或全部映射到内存中,从而可以像访问内存一样快速地访问文件。

文件合并 

文件合并流程:

1、找到要合并的文件并按文件合并的先后进行排序。

2、创建合并文件

3、依次从合并的文件中读取数据向合并文件写入数

文件合并的测试代码 :

//测试文件合并方法@Testpublic void testMerge(){try {//获取源文件File sourceFile = new File("B:\\workspace\\test\\you.ncm");//分块文件目录String chunkPath="B:\\workspace\\test\\chunk\\";//合并后的文件File mergeFile = new File("B:\\workspace\\test\\you1.ncm");if (mergeFile.exists()) {mergeFile.delete();}//创建新的合并文件mergeFile.createNewFile();RandomAccessFile write = new RandomAccessFile(mergeFile,"rw");//指针指向文件顶端write.seek(0);//缓冲区byte[] b = new byte[1024];//获取分块文件数组File file = new File(chunkPath);File[] files = file.listFiles();// 转成集合,便于排序List<File> fileList = Arrays.asList(files);//使用工具类和自定义比较类进行排序Collections.sort(fileList, new Comparator<File>() {@Overridepublic int compare(File o1, File o2) {Integer o1Name = Integer.parseInt(o1.getName());Integer o2Name=Integer.parseInt(o2.getName());return o1Name-o2Name;}});//合并文件for (File file1 : fileList) {RandomAccessFile read = new RandomAccessFile(file1,"r");int len = -1;while ((len = read.read(b)) != -1) {write.write(b, 0, len);}read.close();}write.close();//校验文件FileInputStream fileInputStream = new FileInputStream(sourceFile);FileInputStream mergeFileStream = new FileInputStream(mergeFile);//取出原始文件的md5String originalMd5 = DigestUtils.md5Hex(fileInputStream);//取出合并文件的md5进行比较String mergeFileMd5 = DigestUtils.md5Hex(mergeFileStream);if (originalMd5.equals(mergeFileMd5)) {System.out.println("合并文件成功");} else {System.out.println("合并文件失败");}} catch (Exception e) {e.printStackTrace();}}

视频上传流程 

 

1、前端对文件进行分块。

2、前端上传分块文件前请求媒资服务检查文件是否存在,如果已经存在则不再上传。

3、如果分块文件不存在则前端开始上传

4、前端请求媒资服务上传分块。

5、媒资服务将分块上传至MinIO。

6、前端将分块上传完毕请求媒资服务合并分块。

7、媒资服务判断分块上传完成则请求MinIO合并文件。

8、合并完成校验合并后的文件是否完整,如果不完整则删除文件。

 

测试将分块文件上传至minio

 //将分块文件上传至minio@Testpublic void uploadChunk(){String chunkFolderPath = "B:\\workspace\\test\\chunk\\";File chunkFolder = new File(chunkFolderPath);//分块文件File[] files = chunkFolder.listFiles();//将分块文件上传至miniofor (int i = 0; i < files.length; i++) {try {UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket("testbucket")//桶名.object("chunk/" + i)//存储路径+文件名.filename(files[i].getAbsolutePath()).build();minioClient.uploadObject(uploadObjectArgs);System.out.println("上传分块成功"+i);} catch (Exception e) {e.printStackTrace();}}}

测试通过minio的合并文件

 

//合并文件,要求分块文件最小5M@Testpublic void test_merge() throws Exception {List<ComposeSource> sources = new ArrayList<>();for (int i = 0; i <=7; i++) {ComposeSource composeSource = ComposeSource.builder()//指定分块文件信息.bucket("testbucket").object("chunk/" + (Integer.toString(i)))//目标文件信息.build();sources.add(composeSource);}ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder().bucket("testbucket").object("merge01.npm")//目标文件.sources(sources)//源文件.build();//合并文件minioClient.composeObject(composeObjectArgs);}

测试minio清除分块文件 

//清除分块文件@Testpublic void test_removeObjects(){//合并分块完成将分块文件清除List<DeleteObject> deleteObjects = Stream.iterate(0, i -> ++i).limit(2)//循环几次.map(i -> new DeleteObject("chunk/".concat(Integer.toString(i)))).collect(Collectors.toList());RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder().bucket("testbucket").objects(deleteObjects).build();Iterable<Result<DeleteError>> results = minioClient.removeObjects(removeObjectsArgs);results.forEach(r->{DeleteError deleteError = null;try {deleteError = r.get();} catch (Exception e) {e.printStackTrace();}});}

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

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

相关文章

【busybox记录】【shell指令】tr

目录 内容来源&#xff1a; 【GUN】【tr】指令介绍 【busybox】【tr】指令介绍 【linux】【tr】指令介绍 使用示例&#xff1a; 转换字符 - 默认 转换字符 - 不翻译指定字符数组 此指令目前接触少&#xff0c;用得少&#xff0c;把精力放到其他常用指令上 常用组合指令…

CP AUTOSAR之CANXL Driver详细说明(正在更新中)

本文遵循autosar标准&#xff1a;R22-11 1 简介及功能概述 本规范描述了AUTOSAR 基础软件模块CAN XL 驱动程序的功能、API和配置。   本文档的基础是[1,CiA610-1]和[2,CiA611-1]。假设读者熟悉这些规范。本文档不会再次描述CAN XL 功能。   CAN XL 驱动程序是最低层的一部…

125.两两交换链表中的节点(力扣)

题目描述 代码解决及思路 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), …

一篇迟来的未来展望的博客

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 老师布置的任务&#xff0c;叫写一篇博客&…

04.2.配置应用集

配置应用集 应用集的意思就是&#xff1a;将多个监控项添加到一个应用集里面便于管理。 创建应用集 填写名称并添加 在监控项里面找到对应的自定义监控项更新到应用集里面 选择对应的监控项于应用集

【Sql-02】 求每个省份最新登陆的三条数据

SQL 输出要求数据准备sql查询结果 输出要求 要求输出&#xff0c;userid_1,logtime_1,userid_2,logtime_2,userid_3,logtime_3 数据准备 CREATE TABLE sqltest (province varchar(32) NOT NULL,userid varchar(250) DEFAULT NULL,logtime datetime ) ENGINEInnoDB DEFAULT C…

深度学习--生成对抗网络GAN

GAN简介 让我们先来简单了解一下GAN GAN的全称是Generative Adversarial Networks&#xff0c;中文称为“生成对抗网络”&#xff0c;是一种在深度学习领域广泛使用的无监督学习方法。 GAN主要由两部分组成&#xff1a;生成器和判别器。生成器的目标是尽可能地生成真实的样本数…

如何创建微信小程序?只需3步完成小程序制作

微信&#xff0c;中国最大的社交媒体应用程序&#xff0c;几个月前推出了微信小程序&#xff0c;这一神奇的功能立即大受欢迎。这些小程序让在中国注册的商业实体所有者创建一个小程序来与微信用户互动。这些小程序不需要在用户手机上进行任何安装&#xff0c;只需通过微信应用…

STM32微秒级别延时--F407--TIM1

基本配置&#xff1a; TIM1挂载在APB2总线上&#xff0c;150MHz经过15分频&#xff0c;得到10MHz计数频率&#xff0c;由于disable了自动重装载&#xff0c;所以只需要看下一次计数值是多少即可。 void TIM1_Delay_us(uint16_t us) //使用阻塞方式进行延时&#xff0c;ARR值不…

【C 数据结构-动态内存管理】4. 无用单元收集(垃圾回收机制)

文章目录 【 1. 问题描述与解决方法 】【 2. 中断回收机制 】 【 1. 问题描述与解决方法 】 问题描述 动态存储管理的运行机制可以概括为&#xff1a;当用户发出申请空间的请求后&#xff0c;系统向用户分配内存&#xff1b;用户运行结束释放存储空间后&#xff0c;系统回收内…

Fizzler库+C#:从微博抓取热点的最简单方法

概述 在这篇技术文章中&#xff0c;我们将深入研究如何利用Fizzler库结合C#语言&#xff0c;以实现从微博平台抓取热点信息的功能。微博作为中国乃至全球范围内具有重要影响力的社交媒体平台之一&#xff0c;在互联网信息传播中扮演着举足轻重的角色。通过Fizzler这一强大的.N…

Pytorch 实现情感分析

情感分析 情感分析是 NLP 一种应用场景&#xff0c;模型判断输入语句是积极的还是消极的&#xff0c;实际应用适用于评论、客服等多场景。情感分析通过 transformer 架构中的 encoder 层再加上情感分类层进行实现。 安装依赖 需要安装 Poytorch NLP 相关依赖 pip install t…

JVM学习笔记【基础篇:垃圾回收】

自动垃圾回收 C/C的内存管理 ⚫ 在C/C这类没有自动垃圾回收机制的语言中&#xff0c;一个对象如果不再使用&#xff0c;需要手动释放&#xff0c;否则就会出现 内存泄漏。我们称这种释放对象的过程为垃圾回收&#xff0c;而需要程序员编写代码进行回收的方式为手动回收。 ⚫ …

RTT潘多拉开发板上实现电源管理

简介 随着物联网(IoT)的兴起&#xff0c;产品对功耗的需求越来越强烈。作为数据采集的传感器节点通常需要在电池供电时长期工作&#xff0c;而作为联网的SOC也需要有快速的响应功能和较低的功耗。 在产品开发的起始阶段&#xff0c;首先考虑是尽快完成产品的功能开发。在产品…

数仓开发中期:理论巩固

一、数仓以及商业智能&#xff08;Data Warehousing and Business Intelligence, DW/BI&#xff09;系统 1.1数据操作和数据获取的区别 对所有组织来说&#xff0c;信息都是其最重要的财富之一。信息几乎总是用作两个目的:操作型记录的保存和分析型决策的制定。简单来说&…

Stack数据结构设计模板

第三章 栈、队列、数组 1.栈 1.1 顺序栈 #define MaxSize 20 typedef int ElemType; //顺序栈的定义 typedef struct {ElemType data[MaxSize];int top; }SqStack; // 初始化顺序栈 void InitSqStack(SqStack &S){S.top -1; }; // 入栈(增) bool Push(SqStack &S,El…

WIFI模块UDP电脑端调试

一&#xff0c;两端都是电脑端 1&#xff0c;电脑本机的IP地址 192.168.137.1 2&#xff0c;新建两个不同的连接&#xff0c;注意端口 二&#xff0c;WIFI 模块和电脑端连接 1&#xff0c;设置模块端目标IP和端口&#xff0c;电脑端只接收数据的话&#xff0c;IP、端口可随…

【从零开始学架构 架构基础】架构设计的本质、历史背景和目的

本文是《从零开始学架构》的第一篇学习笔记&#xff0c;主要理解架构的设计的本质定义、历史背景以及目的。 架构设计的本质 分别从三组概念的区别来理解架构设计。 系统与子系统 什么是系统&#xff0c;系统泛指由一群有关联的个体组成&#xff0c;根据某种规则运作&#…

企业终端安全管理软件有哪些?终端安全管理软件哪个好?

终端安全的重要性大家众所周知&#xff0c;关系到生死存亡的东西。 各类终端安全管理软件应运而生&#xff0c;为企业提供全方位、多层次的终端防护。 有哪些企业终端安全管理软件&#xff1f; 一、主流企业终端安全管理软件 1. 域智盾 域智盾是一款专为企业打造的全面终端…

奥威-金蝶BI现金流量表模板,可借鉴、可套用

企业现金流一旦出了问题都是大问题&#xff0c;会直接影响到企业的日常运作&#xff0c;甚至直接关系到企业能不能继续存活&#xff0c;因此现金流量表是企业财务分析中重要报表之一&#xff0c;也是企业监控财务监控情况的重要手段之一。那么这么重要的一份现金流量表该怎么做…