java: 多线程复制文件
2018-01-21 01:58
309 查看
突然想写一个多线程下载的小案例。但是并不知道怎么做,所以想先写一个多线程复制文件的小案例。
搜遍全网,都没有找到一个类似的。不过还是找到一篇有参考价值的博文:jAVA基础 提高文件复制性能之多线程复制文件
以及这篇java多线程复制文件,RandomAccessFile类
想起每次面试都会被问起:怎么实现多线程下载?很慌。每次回答都是支支吾吾的。毕竟,我不能直接说,我都是用开源框架直接实现的,并没有去看过实现源码~ 一种被支配的恐惧,一直笼罩在我内心…
好了,不多说了,贴一下我实现的代码:
首先看 Main.java 这是一个调用类:
可以看到,调用还是比较简单的,不过要传4个参数
然后是
这里重点是
看如下代码片段:
分段复制的大体思路就是:先计算好每一段需要复制的文件的起点和终点,对应的参数就是
起点移动到
然后到终点的时候,就停止复制,把后面的内容留个下个线程去操作:
最后,说明一下,这个多线程复制文件的程序,是不用考虑线程安全的问题的。因为不涉及多个线程对共享数据的写操作。虽然,是多线程共同写目标文件了,但是分工明确,每个线程只写自己的
搜遍全网,都没有找到一个类似的。不过还是找到一篇有参考价值的博文:jAVA基础 提高文件复制性能之多线程复制文件
以及这篇java多线程复制文件,RandomAccessFile类
想起每次面试都会被问起:怎么实现多线程下载?很慌。每次回答都是支支吾吾的。毕竟,我不能直接说,我都是用开源框架直接实现的,并没有去看过实现源码~ 一种被支配的恐惧,一直笼罩在我内心…
好了,不多说了,贴一下我实现的代码:
首先看 Main.java 这是一个调用类:
package com.cat.multi.copy; import java.io.File; import java.io.IOException; /** * Created by cat on 2018/1/20. * 多线程拷贝 */ public class Main { public static void main(String[] args) throws IOException, InterruptedException { String path = Class.class.getClass().getResource("/").getPath(); String rootPath = new File(path).getParentFile().getParentFile().getParentFile().getPath(); File sf = new File(rootPath, "raw/src/memo_methine.pdf"); // src File df = new File(rootPath, "raw/dest/memo_methine_copied.pdf"); // dest if (df.isFile()) { df.delete(); } long srcsize = sf.length(); System.out.println("srcSize==" + srcsize); // long pos = 0; // long end = srcsize / 2 / 1024 * 1024; long pos1 = 0; long end1= srcsize / 2 / 1024 * 1024; Copy copy1 = new Copy(sf.getAbsolutePath(), df.getAbsolutePath(), pos1, end1); long pos2 = srcsize / 2 / 1024 * 1024; long end2 = srcsize; Copy copy2 = new Copy(sf.getAbsolutePath(), df.getAbsolutePath(), pos2, end2); new Thread(copy2).start(); // Thread.sleep(10); new Thread(copy1).start(); } }
可以看到,调用还是比较简单的,不过要传4个参数
srcPath,destPath,pos,end。为啥要4个参数,这里简要说明一下:
srcPath和
destPath就不说了,就是源文件路径,以及复制后的目标路径
pos是啥?是
RandomAccessFile#seek(pos)方法需要的参数。表示偏移位置,从pos 开始去读写数据。
end是啥?既然是多线程复制,也就是表示如果一个文件是
3M的,然后开3个线程去复制,那么,每个线程都去复制
1M的大小就可以了。所以,
end是和
pos组合使用的,表示,当前线程复制的文件的起点位置和终点位置。(可以把文件理解成一个数据流,流就用节点和长度…)
然后是
Copy.java的代码:
package com.cat.multi.copy; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; /** * <pre> * * Created by cat on 2018/1/20. * 小应用:多线程拷贝数据 * 分析一下:多线程拷贝是否需要考虑线程安全? * 1. 是否是多线程运行环境? ---> 是 * 2. 是否需要访问共享数据? ---> 否 * * 为什么说没有访问共享数据,因为调用的时候是为每个线程分别创建了一个Copy 对象 * 3. 操作共享数据是否是多条语句?--> 是 * * </pre> */ public class Copy implements Runnable { private final int bufferSize = 1024; private final String srcPath; private final String dest; private long pos; private long end; /** * @param dest 全路径 --> /data/storage/camera/dog.jpg * @param srcPath 全路径 */ public Copy(String srcPath, String dest, long pos, long end) { this.srcPath = srcPath; this.dest = dest; this.pos = pos; this.end = end; } /** * 传统的读写文件的方式 --> 可用,但是不能实现分段读写文件。 * * @throws IOException io */ private void copy() throws IOException { RandomAccessFile bin = new RandomAccessFile(srcPath, "r"); RandomAccessFile bout = new RandomAccessFile(dest, "rw"); // BufferedInputStream bin = new BufferedInputStream(new FileInputStream(src)); // BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(df)); byte[] buffer = new byte[1024]; int read; while ((read = bin.read(buffer)) != -1) { bout.write(buffer, 0, read); } bout.close(); bin.close(); } /** * need copy 2 * * @throws IOException */ public void copy1() throws IOException, InterruptedException { if (this.pos == this.end) { System.out.println(" 文件已经复制结束了...."); return; } Thread.sleep(100); RandomAccessFile bin = new RandomAccessFile(srcPath, "r"); RandomAccessFile bout = new RandomAccessFile(dest, "rw"); byte[] buffer = new byte[bufferSize]; int read; long total = 0; bin.seek(pos); bout.seek(pos); while ((read = bin.read(buffer)) != -1) { bout.write(buffer, 0, read); total += read; if (total + pos == this.end) { System.out.println("我的任务完成了. 当前完成的数据为:" + total); System.out.println("c1. from:" + pos + " , end=" + end + " , total=" + new File(srcPath).length()); this.pos = this.end; break; } else if (total > this.end) { throw new RuntimeException("end 计算出错了,需要修改程序,否则数据复制会出错..."); } } bout.close(); bin.close(); } @Override public void run() { while (true) { if (this.pos == this.end) { System.out.println(" 文件已经复制结束了...."); break; } try { copy1(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } }
这里重点是
Copy#copy1()这个方法,通过改变
pos实现了对文件的分段复制。
看如下代码片段:
byte[] buffer = new byte[bufferSize]; int read; long total = 0; bin.seek(pos); // 关键点在这里 bout.seek(pos); // in 和 out 都需要 seek() while ((read = bin.read(buffer)) != -1) { bout.write(buffer, 0, read); total += read; if (total + pos == this.end) { System.out.println("我的任务完成了. 当前完成的数据为:" + total); System.out.println("c1. from:" + pos + " , end=" + end + " , total=" + new File(srcPath).length()); this.pos = this.end; break; } else if (total > this.end) { throw new RuntimeException("end 计算出错了,需要修改程序,否则数据复制会出错..."); } }
分段复制的大体思路就是:先计算好每一段需要复制的文件的起点和终点,对应的参数就是
pos , end。然后再复制的时候,按照这个参数去复制就可以了。
起点移动到
pos这里。
bin.seek(pos);bout.seek(pos);
然后到终点的时候,就停止复制,把后面的内容留个下个线程去操作:
if (total + pos == this.end){...break;}
最后,说明一下,这个多线程复制文件的程序,是不用考虑线程安全的问题的。因为不涉及多个线程对共享数据的写操作。虽然,是多线程共同写目标文件了,但是分工明确,每个线程只写自己的
pos,end的数据。
相关文章推荐
- java基础之多线程复制文件代码演示
- Java中使用多线程复制文件
- java多线程实现复制大文件
- java多线程复制文件
- Java简单实现多线程复制文件
- JAVA多线程复制文件
- jAVA基础 提高文件复制性能之多线程复制文件
- 黑马程序员_java用java进行复制文件(考虑使用多线程),能系统自带快吗??
- Java多线程复制文件(转)
- Java多线程复制文件
- JAVA多线程文件复制
- 多线程 java文件复制,文件提取,删除,zip压缩工具
- 使用Java的多线程和IO流写一个文件复制功能类
- java多线程复制文件的实例代码
- Java多线程复制大文件
- java多线程复制文件,RandomAccessFile类
- java 多线程文件复制
- 多线程实现文件复制
- 多线程文件复制程序(4个线程)
- Java实现文件复制