RandomAccessFile流拷贝文件模拟简单的网络断点下载

我们在下载东西可以发现当我们网络断开之后,下载进度依然保存,当网络恢复时,接着断点位置继续下载,其实基于RandomAccessFile流就可以实现这样的操作,下面用个文件拷贝演示一下原理。

java.io.RandomAccessFile

该类的实例支持读取和写入随机访问文件,它既可以读取文件也可以写入文件,只需要在定义构造器时形参第二位声明“r” (可读) “rw” (可读可取),RandomAccessFile对象包含了一个记录指针,当程序新创建一个RandomAccessFile对象时,指针位于0处,当开始读取文件时指针后移,移动的偏移量就是读取的字节数,下面有两个方法可以获取、设置指针位置:
getFilePointer():获取当前指针位置,返回long类型数值
seek(long pos):设置当前指针位置为pos
好了,了解了原理之后我们就可以开始了:

创建RandomAccessFileDemo类

public class RandomAccessFileDemo {
	// 源文件
	File source;
	// 目标文件
	File target;
	// 记录断点指针的文件
	File breakPoint;

	/**
	 * 定义有参构造器用来初始化
	 * 
	 * @param source
	 * @param target
	 * @param breakPoint
	 */
	public RandomAccessFileDemo(File source, File target, File breakPoint) {
		this.source = source;
		this.target = target;
		this.breakPoint = breakPoint;
	}

	/**
	 * 定义文件拷贝方法
	 * 
	 * @throws FileNotFoundException
	 */
	public void copyFile() throws FileNotFoundException {
		// 定义读取流,设置为可读状态
		RandomAccessFile raf1 = new RandomAccessFile(source, "r");
		// 定义写入流,设置为可写可读状态
		RandomAccessFile raf2 = new RandomAccessFile(target+File.separator+source.getName(), "rw");
		// 定义写入流,把指针位置保存在记录断点文件
		RandomAccessFile raf3 = new RandomAccessFile(breakPoint, "rw");
		// 定义变量用来记录read方法实际读取长度
		int len = 0;
		// 定义缓存大小为16字节的字节数组
		byte b[] = new byte[16];
		// 这里我们定义一个“意外”让读写中断
		try {
			// 定义计数器
			int count = 0;
			while ((len = raf1.read(b)) != -1) {
				raf2.write(b, 0, len);
				count++;
				// 计数器到三拷贝中断
				if (count == 3) {
					// 得到断点时读入指针位置,也是恢复时开始读写的位置
					long point = raf1.getFilePointer();
					// 将断点位置记录到保存指针位置文件中
					raf3.writeLong(point);
				    System.out.println("拷贝中断");
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭流
			try {
				raf1.close();
				raf2.close();
				raf3.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}

		}

	}
	/**
	 * 创建recover方法,恢复断点,继续拷贝
	 * 这里我们用来演示,实际开发中不建议这样写(代码重复率太高)
	 * @throws FileNotFoundException
	 */
	public void recover() throws FileNotFoundException{
		        // 定义读取流,设置为可读状态
				RandomAccessFile raf1 = new RandomAccessFile(source, "r");
				// 定义写入流,设置为可写可读状态
				RandomAccessFile raf2 = new RandomAccessFile(target+File.separator+source.getName(), "rw");
				// 定义写入流,把指针位置保存在记录断点文件
				RandomAccessFile raf3 = new RandomAccessFile(breakPoint, "rw");
				// 定义变量用来记录read方法实际读取长度
				int len = 0;
				// 定义缓存大小为16字节的字节数组
				byte b[] = new byte[16];
				/*
				 * 写入文件之前我们要把指针位置设置到断点位置
				 * 先读出保存在文件中指针的位置
				 */	
				try {
					long point=raf3.readLong();
					//将指针位置恢复
					raf1.seek(point);
					raf2.seek(point);
				} catch (IOException e) {
					e.printStackTrace();
				}
				//继续写入文件,从当前指针读写
				try {
					while ((len = raf1.read(b)) != -1) {
						raf2.write(b, 0, len);
					}
					System.out.println("拷贝完成");
				} catch (IOException e) {
					e.printStackTrace();
				}finally {
					try {
						//关流
						raf1.close();
						raf2.close();
						raf3.close();
					} catch (IOException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
					
				}
	}

}

创建测试类

/**
 * 测试
 * @author gq
 *
 */
public class Test {
	
	public static void main(String[] args) throws FileNotFoundException {
		//这里我们用音频文件演示
		File source=new File("D:\\Test\\梅艳芳 - 亲密爱人.mp3");
		File target=new File("D:\\Test\\music");
		File breakPoint=new File("D:\\Test\\pointer.txt");
		RandomAccessFileDemo r=new RandomAccessFileDemo(source, target, breakPoint);
		//先拷贝
		//r.copyFile();
		//从断点位置继续拷贝
		 r.recover();
	}

}

执行了拷贝之后我们发现文件只复制了一部分:
在这里插入图片描述
此时文件打不开.
在这里插入图片描述

下面我们执行第二个方法恢复拷贝,文件与源文件大小一致:
在这里插入图片描述
文件可以正常播放。
在这里插入图片描述

这时我们发现文件已经完全拷贝过去了,其实网络进行下载传输时,也是这个原理,当网路中断时记录断点位置,等网络恢复时继续从断点位置接着下载。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值