Java多线程断点下载 - 随机存取

多线程断点下载的一个基础了解 (初级-本地下载)

也就是说将文件分割成多块儿,以支持多线程下载。

1.RandomAccessFile

1)简单介绍 是一种任意存取流、是处理流的一种,其对象包含一个记录指针能以任意访问的方式,程序可以跳到文件的任意位置进行读写。因而可以利用这个流,利用多线程来实现多断点下载,加快下载速度。

继承于java.lang.Object类,位于java.io包下。

2)构造器

创建实例时需要指定一个mode参数,用来指定访问模式。

本文主要用只读和读写两种模式

3)两个主要方法

-1: long getFilePointer() 获取文件记录指针当前的位置

-2 : void seek(long pos) 将文件指针定位到指定pos位置

位置的单位都是B,即字节

-3 :使用实例:

用任意存取流的对象来调用

randomAccessFile.seek(100); // 将文件指针移动到第100个字节的位置。

2.文件记录指针

这对于本文实现多线程的断点下载很重要,条件基于这个指针指向而设置。

1)简单介绍

"文件记录指针" 通常指的是一个指向文件中某个位置的指针。这个指针可以用于定位文件中的数据,以便读取或写入特定的位置。文件记录指针的概念常常与随机访问文件相关。

2)文件指针的定位

文件指针指示了文件中当前读取或写入的位置。在顺序访问中,文件指针从文件的开头逐渐移动到文件的末尾。而在随机访问中,可以通过文件指针直接跳转到文件的任意位置。

不指定的情况下不会指向已经读写的位置(除了顺序写时,最终会指向文件末尾已经写完的最后一个字节)

3)初始位置

文件记录指针的起始位置为0是一种通用的约定,而不是一个绝对的规定。这约定在计算机科学中是一种普遍的惯例,多数编程语言和文件系统都遵循这个规定。

这种约定的历史起源可以追溯到低级别的硬件和操作系统设计。在很多系统中,文件被认为是一系列的字节或块,这些字节按照从0开始的索引进行编号。因此,将文件记录指针的初始位置设置为0是直观且方便的选择。

当你打开一个文件时,文件记录指针通常会被设置为文件的起始位置,即0。这使得文件指针的移动更容易理解,因为它与文件中的字节索引直接对应。

4)顺序读取的终止位置

指向文件的末尾。

例如图片有888888B则指针最终会指向位置888888B,是同样的。

3.run方法

1)成员变量设置

开始下载的位置和终止下载的位置

两个File对象,方便读写

注意,由于是继承于Tread类的方法,这些变量不是多线程共享的,每个线程都有自己的一套。

2)处理

最后一次要达到规定的线程下载结束位置时,通过处理用于传输的数组大小来使得正好传输到满足要求的数据:

kotlin 复制代码
if ((this.trunPosition < this.start + num + 1024 - 1)){     
     b = new byte[(int) (this.trunPosition - num - this.start + 1)];  
}

这使得该线程下载文件终止的位置能恰好在规定处,使得多个线程的下载能合在一起。而该线程的任意存取流对象的记录指针------>指向规定下载结束位置+1或文件末尾位置

kotlin 复制代码
if(raFin.getFilePointer() >= this.trunPosition){
        //System.out.println(Thread.currentThread().getName()+" "+len);
        //System.out.println(Thread.currentThread().getName()+" "+b.length);
        //System.out.println(raFout.getFilePointer());
        break;
}
ini 复制代码
//采用继承于Thread类的重写run方法创建线程
class DownMuldo extends Thread {
	long start;
	long trunPosition;
	File filein = new File("E:\\BaiduNetdiskDownload\\wen\\query.avi");
	File fileout = new File("E:\\BaiduNetdiskDownload\\wen\\querydownload.avi");
 
	@Override
	public void run() {
 
		long allLength = filein.length();
 
		RandomAccessFile raFin = null;
		RandomAccessFile raFout = null;
 
		byte[] b = new byte[1024];
		int len = 0;
		long num = 0;
		try {
			raFin = new RandomAccessFile(filein, "r");
			raFout = new RandomAccessFile(fileout, "rw");		
			raFin.seek(start);
			raFout.seek(start);
			while (true) {
				if ((this.trunPosition < this.start + num + 1024 - 1)){
					b = new byte[(int) (this.trunPosition - num - this.start + 1)];
				}
				len = raFin.read(b);
				raFout.write(b,0,len);
				num += (long) len;
				System.out.println(Thread.currentThread().getName());
				if(raFin.getFilePointer() >= this.trunPosition){
					//System.out.println(Thread.currentThread().getName()+" "+len);
					//System.out.println(Thread.currentThread().getName()+" "+b.length);
					//System.out.println(raFout.getFilePointer());
					break;
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			
			try {
				if(raFin != null){
					raFin.close();
				}
				if(raFout != null){
					raFout.close();
				}
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
 
	}
}

4.创建线程

初始化专属于线程的一些变量,主要是对起始位置和终止位置的设置,本文采用分割4部分下载。

ini 复制代码
public class MulRoute {
	static boolean flag = true;
	public static void main(String[] args) {
 
		DownMuldo m1 = new DownMuldo();
		DownMuldo m2 = new DownMuldo();
		DownMuldo m3 = new DownMuldo();
		DownMuldo m4 = new DownMuldo();
 
		m1.start = 0;
		m1.trunPosition = m1.filein.length() / 4 - 1;
		m1.setName("下载线程1");
		System.out.println(m1.start);
 
		m2.start = m1.trunPosition + 1;
		m2.trunPosition = m2.start + m1.filein.length() / 4 - 1 - 1;
		m2.setName("下载线程2");
		System.out.println(m2.start);
 
		m3.start = m2.trunPosition + 1;
		m3.trunPosition = m3.start + m1.filein.length() / 4 - 1 - 1;
	    m3.setName("下载线程3");
	    System.out.println(m3.start);
 
		m4.start = m3.trunPosition + 1;
		m4.trunPosition = m1.filein.length();
		m4.setName("下载线程4");
		System.out.println(m4.start);
 
		//m1.start();
		//m2.start();
		//m3.start();
		//m4.start();
 
	}
}

5.总结

1.本文通过仿真,了解多线程断点下载的初级的方法和理念,能够成功 复制/下载 视频、文件、图片等。

2.通过使用,熟悉了文件记录指针。

3.后续有待扩展:通过文件记录指针记录终止下载的位置,用户发出重新下载指令后,从记录的位置开始重新下载。只要明白了随机存取的文件记录指针,这实际不难。

4.期待大家的批评指正,感谢。

相关推荐
斑驳的岁月3 分钟前
MacOs java环境配置+maven环境配置踩坑实录
java·macos·maven
严文文-Chris6 分钟前
方法区、堆、虚拟机栈、寄存器分别存储哪些内容?为什么存储这些内容?
java·开发语言
qq_4850152113 分钟前
Java网络编程干货
java·网络·php
努力的搬砖人.22 分钟前
java爬虫案例
java·经验分享·后端
Miraitowa_cheems31 分钟前
JAVA SE 自我总结
java·开发语言·javase
老马啸西风32 分钟前
java 开源中文的繁简体转换 opencc4j-03-简体还是繁体,你说了算!
java
老马啸西风35 分钟前
java 开源中文的繁简体转换 opencc4j-02-一个汉字竟然对应两个 char?
java
都叫我大帅哥37 分钟前
遍历世界的通行证:迭代器模式的导航艺术
java·后端·设计模式
_沉浮_38 分钟前
Spring AI使用tool Calling和MCP
java·人工智能·spring
Alt.91 小时前
SpringMVC基础三(json)
java·开发语言