网络多线线程下载并合并文件示例

  本示例的采用IO流与多线程下载同一张图片,下载完后进行合并;使用方法内创建线程方式,控制主线程的执行时机,即主线程调用方法,方法内创建线程,再返回调用方法的对象,随即往下执行其他程序,可有效防止主线程的其他方法在下载线程(即其他线程)未完成时执行,而出现数据错位缺失。

  1 import java.io.*;
  2 import java.net.URL;
  3 import java.net.URLConnection;
  4 
  5 /**
  6  * Created by gdkong on 07/11/2017.
  7  */
  8 
  9 public class Test {
 10 
 11     public static void main(String[] args) throws IOException, InterruptedException {
 12         //主线程采用调用方法模式创建其他线程,可让其他线程执行完后才继续执行主线中的其他方法,此方式可控制主线的执行时机
 13       multithreadedDownload ("http://localhost:8080/image/a.jpg","/Users/Shared/abc",3);
 14     }
 15 
 16     /**
 17      * 多线程下载并合并文件,仅适用于Http协议,未尝试其他网络协议
 18      * @param srcPath  下载源文件路径名
 19      * @param destPath 保存文件夹路径名
 20      * @param count    指定线程个数
 21      */
 22     public static void multithreadedDownload(String srcPath, String destPath, int count) throws IOException, InterruptedException {
 23 
 24         //定义一个文件下载的文件夹路径
 25         File dir = new File (destPath);
 26         if (!dir.exists ()) {
 27             dir.mkdirs ();
 28         }
 29         long total = getFileLength (srcPath);
 30         //开启下载线程
 31         OpenMultithreadedDownload (srcPath, dir, total, count);
 32 
 33         //获取文件的后缀名
 34         String suffix = srcPath.substring (srcPath.lastIndexOf ("."));
 35         //合并文件
 36         FileUtils.merge (dir, suffix);
 37 
 38         System.out.println ("文件下载完成");
 39     }
 40 
 41     /**
 42      * 多线程下载块
 43      * @param path 下载源文件路径名
 44      * @param dir 目标文件存储目录
 45      * @param total 下载源文件大小
 46      * @param count 指定线程个数
 47      */
 48     private static void OpenMultithreadedDownload(String path, File dir, long total, int count) throws InterruptedException {
 49 
 50         //计算出每个线程平均现在的字节个数
 51         long size = total / count;
 52         //使用循环,计算每个线程下载开始和结束位置
 53         for (int i = 1; i <= count; i++) {
 54             //开始位置
 55             long starIndex = (i - 1) * size;
 56             //结束位置
 57             long endIndex = i * size - 1;
 58             //最后一个线程
 59             if (i == 3) {
 60                 endIndex = total - 1;
 61             }
 62             DownloadThread dt = new DownloadThread (path, dir, starIndex, endIndex, i);
 63             dt.start ();
 64         }
 65     }
 66 
 67     /**
 68      * 获取下载源文件大小
 69      * @param path 下载源文件路径名
 70      * */
 71     public static long getFileLength(String path) throws IOException {
 72 
 73         URL url = new URL (path);
 74         //获得连接对象
 75         URLConnection con = url.openConnection ();
 76         long total = con.getContentLengthLong ();
 77         return total;
 78     }
 79     /**
 80      * 合并文件功能
 81      * @param dir 源文件存储的父目录
 82      * @param suffix 文件的后缀名,用于过滤文件
 83      */
 84     public static void merge(File dir,String suffix) throws IOException {
 85 
 86         File[] files = dir.listFiles (FileUtils.getFileFilter (suffix,false));
 87         FileOutputStream fos = getFileOutputStream (dir, files[0]);
 88 
 89         for(File file : files){
 90             FileInputStream fis = new FileInputStream (file);
 91             int len;
 92             byte[] buf = new byte[8192];
 93             while ((len=fis.read (buf)) != -1){
 94                 fos.write (buf,0,len);
 95             }
 96             fis.close ();
 97             //把已经合并过的文件删除
 98             file.delete ();
 99         }
100         fos.close ();
101     }
102     //获取合并文件输出流
103     private static FileOutputStream getFileOutputStream(File dir, File file) throws FileNotFoundException {
104         File file1 = file;
105         String name = file1.getName ();
106         name = name.substring (1);
107         File destFile = new File (dir,name);
108         return new FileOutputStream (destFile);
109     }
110     /**
111      * 文件过滤器
112      * @param suffix 文件后缀名
113      * @param containDirectory 是否显示子文件夹文件,true为显示,false不显示
114      */
115     public static FileFilter getFileFilter(String suffix,boolean containDirectory) {
116         return new FileFilter () {
117             @Override
118             public boolean accept(File file) {
119                 String name = file.getName ();
120                 boolean destFormat = file.isFile()&& name.endsWith(suffix);
121                 boolean b;
122 
123                 b = containDirectory && file.isDirectory ();
124 
125                 if (destFormat || b) return true;
126                 else return false;
127             }
128         };
129     }
130 }
131 
132 //下载线程代码
133 class DownloadThread extends Thread {
134 
135     private final String path;
136     private final File dir;
137     private final long startIndex;
138     private final long endIndex;
139     private final int threadID;
140   //使用构造方法传入参数
141     public DownloadThread(String path, File dir, long startIndex,
142                           long endIndex, int threadID) {
143         this.path = path;
144         this.dir = dir;
145         this.startIndex = startIndex;
146         this.endIndex = endIndex;
147         this.threadID = threadID;
148     }
149     @Override
150     public void run() {
151         try {
152             InputStream in = getInputStream ();
153             FileOutputStream fos = getFileOutputStream ();
154             int len ;
155             byte[] arr = new byte[8192];
156             while ((len = in.read (arr)) != -1){
157                 fos.write (arr,0,len);
158             }
159             in.close ();
160             fos.close ();
161         } catch (Exception e) {
162             e.printStackTrace ();
163         }
164 
165     }
166     //获取下载输出流
167     private FileOutputStream getFileOutputStream() throws FileNotFoundException {
168         //获取到文件的名字
169         int index = path.lastIndexOf ("/")+1;
170         String name = path.substring (index);
171         File file = new File (dir,threadID+name);//创建目标文件键,防止文件覆盖
172         //创建一个输出流
173         return new FileOutputStream (file);
174     }
175     //获取下载的输入流
176     private InputStream getInputStream() throws IOException {
177         //创建一个URL对象
178         URL url= new URL (path);
179         //获取到连接对象
180         URLConnection con = url.openConnection ();
181         con.setRequestProperty ("Range","bytes="+startIndex+"-"+endIndex);
182         //获取到输入流
183         return con.getInputStream ();
184     }
185 }

 

posted @ 2017-11-08 11:23  gdwkong  阅读(1054)  评论(0编辑  收藏  举报