RandomAccessFile实现断点续传

断点续传是指在文件传输过程中,当传输中断或失败时,能够恢复传输并继续从上次中断的位置继续传输。

RandomAccessFile类

RandomAccessFile是Java提供的一个用于文件读写的类,它可以对文件进行随机访问,即可以直接跳转到文件的任意位置进行读写操作。

seek()方法将文件指针移动到指定位置。这样可以在文件中随机访问不同的位置。(绝对定位)
skipBytes()方法用于将文件指针向后移动指定的字节数。这个方法可以用于跳过一定数量的字节,以便在文件中定位到需要读取或写入的位置。(相对定位)
read()方法从当前指针处读取数据,也可以使用readFully()方法读取一定长度的数据。
write()方法向文件中指定位置写入数据,也可以使用writeBytes()方法将字节数组写入文件。

断点续传原理

RandomAccessFile的seek()方法是断点续传的关键.我们将文件资源分成若干块,每个线程负责完成每块资源的传输。

实现断点续传

实现断点续传可以通过以下步骤来完成:

  1. 获取原始文件大小:在开始传输之前,获取原始文件的总大小(以字节为单位),可以通过File类的length()方法获取。
  2. 设置传输起始位置:根据需求,记录或设置已经传输完成的字节数,作为起始传输位置
  3. 创建 RandomAccessFile 对象:使用 RandomAccessFile 类来进行文件读写操作,并设置以读或写方式打开文件。
  4. 设置文件指针位置:使用 seek(long position) 方法将文件指针定位到起始传输位置。
  5. 开始传输:使用合适的传输方式 (如通过网络传输数据) 将文件内容传输到目标位置。
  6. 更新已传输的字节数:在传输过程中,记录已经成功传输的字节数,可通过文件指针的位置与起始传输位置的差值得出。
  7. 传输完成检查:在传输过程中,检查是否已经传输完整个文件,可以比较已传输的字节数与原始文件的总大小。
  8. 完成传输:完成传输后,关闭文件资源。

实现代码

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;public class FileUtils {/*** 支持断点续传* @src 拷贝的原文件* @desc 拷贝的位置* @threadNum 开启的线程数*/public static void transportFile(File src, File desc, int threadNum) throws Exception {// 每一个线程读取的大小Long part = (long)Math.ceil(src.length() / threadNum);// 存储多个线程、用于阻塞主线程List<Thread> list = new ArrayList<>();// 定义一个基于多线程 的 hashmap 高并发mapfinal Map<Integer, Long> map = new ConcurrentHashMap<>();// 读取 日志文件中的数据String[] $data = null ;String logName = desc.getCanonicalPath() + ".log";File fl = new File(logName);if (fl.exists()) {BufferedReader reader = new BufferedReader(new FileReader(fl));String data = reader.readLine();// 拆分 字符串$data = data.split(",");reader.close();}final String[] _data = $data ;for (int i = 0; i < threadNum; i++) {final int k = i ;Thread thread = new Thread(() -> {// 线程具体要做的事情RandomAccessFile log = null ;try {RandomAccessFile in = new RandomAccessFile(src, "r");RandomAccessFile out = new RandomAccessFile(desc, "rw");log = new RandomAccessFile(logName, "rw");// 从指定位置读in.seek(_data ==null ?k * part : Long.parseLong(_data[k]) );out.seek(_data ==null ?k * part :  Long.parseLong(_data[k]) );byte[] bytes = new byte[1024 * 2];int len = -1, plen = 0;while (true) {len = in.read(bytes);if (len == -1) {break;}// 如果不等于 -1 , 则 累加求和plen += len;// 将读取的字节数,放入 到 map 中map.put(k,  plen + (_data ==null ?k * part : Long.parseLong(_data[k])) );// 将读取到的数据、进行写入out.write(bytes, 0, len);// 将 map 中的数据进行写入文件中log.seek(0); // 直接覆盖全部文件StringJoiner joiner = new StringJoiner(",");map.forEach((key, val)-> joiner.add(String.valueOf(val)));log.write(joiner.toString().getBytes(StandardCharsets.UTF_8));if (plen + (_data ==null ? k * part : Long.parseLong(_data[k])) >= (k+1) * part ) {break;}}} catch (Exception e) {e.printStackTrace();}finally {try {if (log !=null) log.close();} catch (IOException e) {e.printStackTrace();}}});thread.start();// 把这5个线程保存到集合中list.add(thread);}for(Thread t : list) {t.join(); // 将线程加入,并阻塞主线程}// 读取完成后、将日志文件删除即可new File(logName).delete();}/*** 支持断点续传* @src 拷贝的原文件* @desc 拷贝的位置*/public static void transportFile(File src, File desc) throws Exception {transportFile(src, desc, 5);}public static void transportFile(String src, String desc) throws Exception {transportFile(new File(src), new File(desc));}
}

 测试

需要上传的文件资源

 

 将iso资源文件上传到指定目录 

 在上传文件过程中中断程序,模拟文件资源因为网络原因中断了

当前文件资源还未上传完全,并且有一个日志去标志文件上传进度 

 日志文件标志了每个线程进度

 重新执行程序,模拟重新上传文件

 

剩余文件上传完毕,进度日志也被删除 

 

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

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

相关文章

IntelliJ IDEA 控制台中文乱码的四种解决方法

前言 IntelliJ IDEA 如果不进行配置的话&#xff0c;运行程序时控制台有时候会遇到中文乱码&#xff0c;中文乱码问题非常严重&#xff0c;甚至影响我们对信息的获取和程序的跟踪。开发体验非常不好。 本文中我总结出四点用于解决控制台中文乱码问题的方法&#xff0c;希望有助…

scrapy爬取图片

文章目录 ImagesPipeline使用步骤&#xff1a;1. 数据解析&#xff1a; 获取图片的地址 & 2. 将存储图片地址的item提交到指定的管道类&#xff08;hotgirls.py&#xff09;3. 在管道文件中自制一个基于ImagesPipeLine的一个管道类&#xff01;&#xff01;天大的坑 &#…

ChatGPT Prompting开发实战(十二)

一、如何开发prompts实现个性化的对话方式 通过设置“system”和“user”等roles&#xff0c;可以实现个性化的对话方式&#xff0c;并且可以结合参数“temperature”的设定来差异化LLM的输出内容。在此基础上&#xff0c;通过构建一个餐馆订餐对话机器人来具体演示对话过程。…

git你学“废”了吗?——git撤销操作指令详解

git你学“废”了吗&#xff1f;——git撤销操作指令详解&#x1f60e; 前言&#x1f64c;撤销的本质撤销修改情况一&#xff1a;撤销工作区的修改方式一&#xff1a;方式二&#xff1a;演示截图&#xff1a; 撤销修改情况二&#xff1a;撤销暂存区和工作区的修改操作截图&#…

为什么字节大量用GO而不是Java?

见字如面&#xff0c;我是军哥。 我看很多程序员对字节编程语言选型很好奇&#xff0c;为此我还特地问了在字节的两位4-1的技术大佬朋友&#xff0c;然后加上自己的思考&#xff0c;总结了一下就以下 2 个原因&#xff1a; 1、 选型上没有历史包袱 字节的早期的程序员大多来自于…

CISSP学习笔记:PKI和密码学应用

第七章 PKI和密码学应用 7.1 非对称密码学 对称密码系统具有共享的秘钥系统&#xff0c;从而产生了安全秘钥分发的问题非对称密码学使用公钥和私钥对&#xff0c;无需支出复杂密码分发系统 7.1.1 公钥与私钥 7.1.2 RSA&#xff08;兼具加密和数字签名&#xff09; RSA算法…

[论文笔记]UNILM

引言 今天带来论文Unified Language Model Pre-training for Natural Language Understanding and Generation的笔记,论文标题是 统一预训练语言模型用于自然语言理解和生成。 本篇工作提出了一个新的统一预训练语言模型(Unifield pre-trained Language Model,UniLM),可以同…

Linux基本操作符(2)

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 关于Linux的操作符&#xff0c;在上篇博客中我们已经讲述了一些&#xff0c;都是Linux最基本的操作符。今天我们继续了解一些关于对文件及目录增删查改的操作符&#xff0c;话不多说我们直接上内容。 目录 rm指令的回…

Git/GitHub/Idea的搭配使用

目录 1. Git 下载安装1.1. 下载安装1.2. 配置 GitHub 秘钥 2. Idea 配置 Git3. Idea 配置 GitHub3.1. 获取 GitHub Token3.2. Idea 根据 Token 登录 GitHub3.3. Idea 提交代码到远程仓库3.3.1. 配置本地仓库3.3.2. GitHub 创建远程仓库1. 创建单层目录2. 创建多层目录3. 删除目…

大数据-玩转数据-Flink Sql 窗口

一、说明 时间语义&#xff0c;要配合窗口操作才能发挥作用。最主要的用途&#xff0c;当然就是开窗口然后根据时间段做计算了。Table API和SQL中&#xff0c;主要有两种窗口&#xff1a;分组窗口&#xff08;Group Windows&#xff09;和 含Over字句窗口&#xff08;Over Win…

卤制品配送经营商城小程序的用处是什么

卤制品也是食品领域重要的分支&#xff0c;尤其对年轻人来说&#xff0c;只要干净卫生好吃价格合理&#xff0c;那复购率宣传性自是不用说&#xff0c;而随着互联网发展&#xff0c;传统线下门店也须要通过线上破解难题或进一步扩大生意。 而商城小程序无疑是商家通过线上私域…

字符串函数与内存函数讲解

文章目录 前言一、字符串函数1.求字符串长度strlen 2.长度不受限制的字符串函数(1)strcpy(2)strcat(3)strcmp 3.长度受限制的字符串函数(1)strncpy(2)strncat(3)strncmp 4.字符串查找(1)strstr(2)strtok 5.错误信息报告(1)strerror(2)perror 二、内存函数1.memcpy2.memmove3.me…

Neural Networks for Fingerprint Recognition

Neural Computation ( IF 3.278 ) 摘要&#xff1a; 在采集指纹图像数据库后&#xff0c;设计了一种用于指纹识别的神经网络算法。当给出一对指纹图像时&#xff0c;算法输出两个图像来自同一手指的概率估计值。在一个实验中&#xff0c;神经网络使用几百对图像进行训练&…

第 365 场 LeetCode 周赛题解

A 有序三元组中的最大值 I 参考 B B B 题做法… class Solution { public:using ll long long;long long maximumTripletValue(vector<int> &nums) {int n nums.size();vector<int> suf(n);partial_sum(nums.rbegin(), nums.rend(), suf.rbegin(), [](int x…

golang工程——protobuf使用及原理

相关文档 源码&#xff1a;https://github.com/grpc/grpc-go 官方文档&#xff1a;https://www.grpc.io/docs/what-is-grpc/introduction/ protobuf编译器源码&#xff1a;https://github.com/protocolbuffers/protobuf proto3文档&#xff1a;https://protobuf.dev/programmin…

加入PreAuthorize注解鉴权之后NullPointerException报错

记录一次很坑的bug&#xff0c;加入PreAuthorize注解鉴权之后NullPointerException报错&#xff0c;按理来说没有权限应该403报错&#xff0c;但是这个是500报错&#xff0c;原因是因为controller层的service注入失败&#xff0c;然而我去掉注解后service注入成功&#xff0c;并…

使用VSCODE 调试ros2具体设置

vscode 调试 ROS2 张得帅&#xff01; 于 2023-09-09 15:39:39 发布 456 收藏 1 文章标签&#xff1a; vscode ros2 版权 1、在下列目录同层级找到.vscode文件夹 . ├── build ├── install ├── log └── src 2、 安装ros插件 3、创建tasks.json文件&#xff0c;添…

二十七、[进阶]MySQL默认存储引擎InnoDB的简单介绍

1、MySQL体系结构 MySQL大致可以分为连接层、服务层、引擎层、存储层四个层&#xff0c;这里需要注意&#xff0c;索引的结构操作是在存储引擎层完成的&#xff0c;所以不同的存储引擎&#xff0c;索引的结构是不一样的。 &#xff08;1&#xff09;体系结构示意图 &#xff0…

国庆10.01

TCPselect 代码 服务器 #include<myhead.h> #include<sqlite3.h> #define PORT 6666 //端口号 #define IP "192.168.0.104" //IP地址//键盘事件 int jp(fd_set tempfds,int maxfd) {char buf[128] ""; //用来接收数据char buf1[128] …

【算法|贪心算法系列No.2】leetcode2208. 将数组和减半的最少操作次数

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…