前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >RandomAccessFile 解决多线程下载及断点续传

RandomAccessFile 解决多线程下载及断点续传

作者头像
码农架构
发布于 2021-12-27 09:13:38
发布于 2021-12-27 09:13:38
1.7K00
代码可运行
举报
文章被收录于专栏:码农架构码农架构
运行总次数:0
代码可运行

导读:本篇文章主要介绍RandomAccessFile,该类是IO流体系中功能最丰富的文件内容访问类,既可以读取文件内容,也可以向文件输出数据。总结本篇文章希望对从事相关工作的同学能够有所帮助或者启发

一、背景

在针对文件处理当网络环境不好,出现上传失败的时候,可以对失败的Part进行独立的重试,而不需要重新上传其他的Part;中途暂停之后,可以从上次上传完成的Part的位置继续上传。或者要上传到OSS的本地文件很大的时候,可以并行上传多个Part以加快上传;再或者面对一些文件比较大时,我们需要对大文件进行切割分批上传完后再合并处理。

二、RandomAccessFile简介

RandomAccessFile既可以读取文件内容,也可以向文件输出数据。同时,RandomAccessFile支持“随机访问”的方式,程序快可以直接跳转到文件的任意地方来读写数据。

由于RandomAccessFile可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择

与OutputStream、Writer等输出流不同的是,RandomAccessFile允许自由定义文件记录指针,RandomAccessFile可以不从开始的地方开始输出,因此RandomAccessFile可以向已存在的文件后追加内容。如果程序需要向已存在的文件后追加内容,则应该使用RandomAccessFile。

二、RandomAccessFile方法介绍

从类图中可以看出RandomAccessFile实现DataInput和DataOutput数据写入和数据写出函数,下面是具体实现函数声明。

▐ RandomAccessFile的构造函数

RandomAccessFile类有两个构造函数,其实这两个构造函数基本相同,只不过是指定文件的形式不同—。

一个需要使用String参数来指定文件名

另一个个使用File参数来指定文件本身。

除此之外,创建RandomAccessFile对象时还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,一共有4种模式。

  • **"r" : ** 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
  • "rw": 打开以便读取和写入。
  • "rws": 打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
  • "rwd" : 打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。

▐ RandomAccessFile的重要方法

RandomAccessFile类包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以自由的移动记录指针,即可以向前移动,也可以向后移动。RandomAccessFile包含了以下两个方法来操作文件的记录指针.

  • long getFilePointer(); 返回文件记录指针的当前位置
  • void seek(long pos); 将文件记录指针定位到pos位置

三、RandomAccessFile的使用

▐ 指定位置读取文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    RandomAccessFile accessFile = null;
    try {
        File file = new File(filePath);
        accessFile = new RandomAccessFile(file, "r");

        // 获取 RandomAccessFile对象文件指针的位置,初始位置为0
        log.debug("输入内容:{}", accessFile.getFilePointer());

        // 移动文件记录指针的位置
        accessFile.seek(1000);

        byte[] b = new byte[1024];
        int hasRead = 0;
        //循环读取文件
        while ((hasRead = accessFile.read(b)) > 0) {
            //输出文件读取的内容
            System.out.print(new String(b, 0, hasRead));
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        accessFile.close();
    }
}

在上面的程序的关键代码两处,一处是创建了RandomAccessFile对象,该对象以只读模式打开了文件,这意味着RandomAccessFile文件只能读取文件内容,不能执行写入。第二处调用了seek(1000)方法,是指把文件的记录指针定位到1000字节的位置。也就是说程序将从1000字节开始读取数据。其他部分的代码的读取方式和其他的输入流没有区别。

▐ 向文件中追加内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    RandomAccessFile accessFile = null;
    File file = null;
    try {
        file = new File(filePath);
        // 以读写的方式打开一个RandomAccessFile对象
        accessFile = new RandomAccessFile(file, "rw");

        //将记录指针移动到该文件的最后
        accessFile.seek(accessFile.length());

        //向文件末尾追加内容
        accessFile.writeChars("这是追加内容。。");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        accessFile.close();
    }
}

上面代码先以读,写方式创建了一个RandomAccessFile对象,然后将文件记录指针移动到最后,接下来使用RandomAccessFile向文件中写入内容。和其他输出例OutputStream的方式相同。每运行一次上面的程序,就能发现text.txt文件中多添加了一行内容。

▐ 向文件指定位置插入内容

注:RandomAccessFile不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,则新输出的内容会覆盖文件原有的内容,如果需要向指定位置插入内容,程序需要先把插入点后面的内容写入缓存区,等把需要插入的数据写入到文件后,再将缓存区的内容追加到文件后面。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 向文件指定位置插入内容
 *
 * @param filePath     源文件路径
 * @param pos          插入文件指定位置
 * @param writeContent 写入内容
 */
private static void readFileThenWrite(String filePath, long pos, String writeContent) throws IOException {
    RandomAccessFile raf = null;
    File tempFile = File.createTempFile("tmp", null);
    tempFile.deleteOnExit();
    try {
        // 以读写的方式打开一个RandomAccessFile对象
        raf = new RandomAccessFile(new File(filePath), "rw");

        // 创建一个临时文件来保存插入点后的数据
        FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
        FileInputStream fileInputStream = new FileInputStream(tempFile);

        // 把文件记录指针定位到pos位置
        raf.seek(pos);
        raf.seek(pos);

        //------------将插入点后的内容读入临时文件中保存------------
        byte[] bytes = new byte[64];
        //用于保存实际读取的字节数据
        int hasRead = 0;
        //使用循环读取插入点后的数据
        while ((hasRead = raf.read(bytes)) != -1) {
            //将读取的内容写入临时文件
            fileOutputStream.write(bytes, 0, hasRead);
        }

        //------------用于插入内容 ------------
        //把文件记录指针重新定位到pos位置
        raf.seek(pos);

        //追加需要插入的内容
        raf.write(writeContent.getBytes());

        //追加临时文件中的内容
        while ((hasRead = fileInputStream.read(bytes)) != -1) {
            //将读取的内容写入临时文件
            raf.write(bytes, 0, hasRead);
        }
    } catch (Exception e) {
        throw e;
    }
}

上面的程序使用File类的createTempFile方法创建了一个临时文件(该文件将在JVM退出后被删除),用于保存被插入点后面的内容。程序先将文件中插入点后的内容读入临时文件中,然后重新定位到插入点,将需要插入的内容添加到文件后面,最后将临时文件的内容添加到文件后面,通过这个过程就可以向指定文件,指定位置插入内容。每次运行上面的程序,都会看到文件中多了一行内容。

四、总结

通过阅读RandomAccessFile源码,你会发现虽然方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其他IO节点。

但是由于RandomAccessFile可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,而不是把文件从头读到尾,因此RandomAccessFile的一个重要使用场景就是网络请求中的多线程下载及断点续传。

本篇文章主要介绍RandomAccessFile,该类是IO流体系中功能最丰富的文件内容访问类,既可以读取文件内容,也可以向文件输出数据,总结本篇文章主要是为了承接上篇文章 《微服务架构 | 怎样解决超大附件分片上传?》的话题对于文件分片的处理的一个知识点的补充。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
多线程断点下载
多线程断点下载 多线程下载 public class MultiThreadDownloader { private URL url; // 目标地址 private File file; // 本地文件 private long threadLen; // 每个线程下载多少 private static final int THREAD_AMOUNT = 3; // 线程数 private static final String D
xiangzhihong
2018/01/26
8390
Android 网络学习之使用多线程下载,支持断点续传
既然本节是学习如何使用多线程下载,那我们先要明白什么是多线程下载,在搞明白什么是多线程下载之前,需要先知道什么是单线程下载。
DragonKingZhu
2022/05/08
7090
Android 网络学习之使用多线程下载,支持断点续传
Java I/O流输入输出,序列化,NIO,NIO.2
Java IO流 File类: File类是java.io包下代表和平台无关的文件和目录,File不能访问文件内容本身。 File类基本操作: System.out.println("判断文件是否存在:"+file.exists());//判断文件是否存在,返回Boolean值 System.out.println("创建文件夹:"+file.mkdir());//创建文件夹,只能创建一层,返回Boolean值 System.out.println("文件目录
二十三年蝉
2018/07/05
1.5K0
Java---多线程断点下载
http://blog.csdn.net/jwzhangjie/article/details/9772247
bear_fish
2018/09/19
1.1K0
【java筑基】IO流进阶之文件随机访问、序列化与反序列化
RandomAccessFile支持对于文件的随机访问(而不是只能从头开始读写),创建RandomAccessFile对象时需要传入mode参数,该参数有4个值:r(read), rw(read,write), rws(read, write and store data and file into device memory),rwd((read, write and store file into device memory).
半旧518
2022/10/26
2050
【java筑基】IO流进阶之文件随机访问、序列化与反序列化
断点续传原理分析
,文件的传输是一项至关重要的功能,也是资源共享的基础。无论是HTTP、FTP等协议,都支持文件的传输。然而,由于网络的不稳定性或其他原因,文件传输过程中可能会中断。为了解决这个问题,断点续传技术应运而生。
炒香菇的书呆子
2024/10/12
5160
撸了个多线程断点续传下载器,我从中学习到了这些知识
感谢看客老爷点进来了,周末闲来无事,想起同事强哥的那句话:“你有没有玩过断点续传?” 当时转念一想,断点续传下载用的确实不少,具体细节嘛,真的没有去思考过啊。这不,思考过后有了这篇文章。感谢强哥,让我有了一篇可以水的文章,下面会用纯 Java 无依赖实现一个简单的多线程断点续传下载器。
未读代码
2020/07/28
9550
撸了个多线程断点续传下载器,我从中学习到了这些知识
Android多线程+单线程+断点续传+进度条显示下载
效果图 download.gif 白话分析: 多线程:肯定是多个线程咯 断点:线程停止下载的位置 续传:线程从停止下载的位置上继续下载,直到完成任务为止。 核心分析: 断点: 当前线程已经下载的数
用户2032165
2018/06/05
2.1K0
Java IO详解
java技术学习之道 每天分享各种技术文章 作者:一面千人 来源:cnblogs.com/Evsward Java I/O 流是一组有顺序的,有起点和终点的字节集合。是对设备文件间数据传输的总称和抽象。 在IO中涉及的设备文件包括文件、控制台、网络链接等,这其中又根据流的方向可以将两端的设备文件分为数据源对象和接收端对象 数据源对象:有能力产出数据 接收端对象:有能力接收数据 而IO流实际上屏蔽了在实际设备中的处理数据的细节,这些处理方式也叫通信方式可以包括顺序、随机存取、缓冲、二进制、按字符、按字节、按
Tanyboye
2018/07/02
1.1K0
实战篇:断点续传?文件秒传?手撸大文件上传
最近接到一个新的需求,需要上传2G左右的视频文件,用测试环境的OSS试了一下,上传需要十几分钟,再考虑到公司的资源问题,果断放弃该方案。
阿Q说代码
2021/09/09
9991
实战篇:断点续传?文件秒传?手撸大文件上传
Java之多线程断点下载的实现
RandomAccessFile类: 此类的实例支持对随机訪问文件的读取和写入。随机訪问文件的行为相似存储在文件系统中的一个大型 byte 数组。
全栈程序员站长
2022/02/02
6810
Java之多线程断点下载的实现
android学习笔记----多线程断点续传下载原理设计
android实现(HttpURLConnection)的Demo源码:https://github.com/liuchenyang0515/MultithreadBreakpointDowload
砖业洋__
2023/05/06
3150
android学习笔记----多线程断点续传下载原理设计
编程语言的基础——搞定JavaIO
关键字:IO基础,JUnit生命周期,字节流,字符流,字符编码,对象流,序列化,反序列化 Java I/O 流是一组有顺序的,有起点和终点的字节集合。是对设备文件间数据传输的总称和抽象。 在IO中涉及的设备文件包括文件、控制台、网络链接等,这其中又根据流的方向可以将两端的设备文件分为数据源对象和接收端对象 数据源对象:有能力产出数据 接收端对象:有能力接收数据 而IO流实际上屏蔽了在实际设备中的处理数据的细节,这些处理方式也叫通信方式可以包括顺序、随机存取、缓冲、二进制、按字符、按字节、按行等。 字节
文彬
2018/05/08
1.4K0
Java单线程文件下载,支持断点续传功能
程序下载文件时,有时会因为各种各样的原因下载中断,对于小文件来说影响不大,可以快速重新下载,但是下载大文件时,就会耗费很长时间,所以断点续传功能对于大文件很有必要。
JQ实验室
2022/02/09
1.1K0
如何使用Java语言实现文件分片上传和断点续传功能?
在Web应用程序中,文件上传是比较常见的功能。但是,如果要上传大文件,则可能会出现上传时间过长、网络中断等问题,因此需要实现文件分片上传和断点续传功能。本文将介绍如何使用Java语言实现文件分片上传和断点续传功能。
网络技术联盟站
2023/06/05
1.5K1
微服务架构 | 怎样解决分片上传及断点续传?
导读:分片上传、断点续传,这两个名词对于做过或者熟悉文件上传的朋友来说应该不会陌生,总结本篇文章希望对从事相关工作的同学能够有所帮助或者启发。
码农架构
2021/12/27
2.2K0
微服务架构  |  怎样解决分片上传及断点续传?
Android模拟多线程下载
本DEMO采用Executor框架来实现多线程的下载。 Executor原理:任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) 。Executor在执行时使用内部的线程池完成操作。 本博文演示的从服务端多线程下载图片主要是通过HTTP请求头的Range,在线程池中初始化线程数,然后根据算法去计算,每个线程去下载指定Range范围的资源,每个线程现在完成后发送Message消息给主线程的handler ,当所有的线程都下载完成后,handler主动更新主线程UI。 详细代码请移步本人GITHUB
小小工匠
2021/08/16
3990
Java的文件读写操作
当我们读写文本文件的时候,采用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader。其中最重要的类是InputStreamReader, 它是字节转换为字符的桥梁。你可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如GBK等。使用FileReader读取文件:
全栈程序员站长
2022/09/17
1.2K0
Java的文件读写操作
RandomAccessFile简介与使用
今儿翻阅jdk源码的时候,无意间发现了RandomAccessFile这个类,从来没见过,也没使用过,带着好奇心,我决定深入了解一下这个类的意义和使用方法。
allsmallpig
2021/02/25
5690
断点续传的例子
package com.test.bsecond.y_2020.month_01.day0113; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; public class DuanFile { public static void main(String[] args) { try { String path = "https://s2.ax1x.
Dream城堡
2022/01/07
2K0
推荐阅读
相关推荐
多线程断点下载
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验