温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么在java中利用多线程实现文件下载

发布时间:2021-05-27 17:58:34 来源:亿速云 阅读:229 作者:Leah 栏目:编程语言

怎么在java中利用多线程实现文件下载?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

1、DownloadManager类

import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List;   public class DownloadManager implements Runnable {  // 保存路径  private String savePath;  // 总的下载线程数  private int threadNum;  // 下载的链接地址  private String urlFile;  // 是否下载开始  private boolean isStarted;  // 用于监视何时合并文件存放Thread的list  private List<DownloadThread> downloadList = new ArrayList<DownloadThread>();    public DownloadManager(String savePath, int threadNum, String urlFile) {  super();  this.savePath = savePath;  this.threadNum = threadNum;  this.urlFile = urlFile;  }    // 最终调用线程下载。本线程中调用分线程。  public void action() {  new Thread(this).start();  }    public void run() {  long t1 = System.currentTimeMillis();  System.out.println(t1);  // 如果没有下载 , 就开始 , 并且将已经下载的变量值设为true  if (!isStarted) {  startDownload();  isStarted = true;  }  while (true) {  // 初始化认为所有线程下载完成,逐个检查  boolean finish = true;  // 如果有任何一个没完成,说明下载没完成,不能合并文件  for (DownloadThread thread : downloadList) {  if (!thread.isFinish()) {  finish = false;  break;  }  }  // 全部下载完成才为真  if (finish) {  // 合并文件  mergeFiles();  // 跳出循环 , 下载结束  break;  }  // 休息一会 , 减少cpu消耗  try {  Thread.sleep(1000);  } catch (InterruptedException e) {  e.printStackTrace();  }  }  long t2 = System.currentTimeMillis();  System.out.println(t2);  System.out.println("下载用时:" + (t2 -t1));  }    public void startDownload() {  // 得到每个线程开始值 , 下载字节数大小  int[][] posAndLength = getPosAndLength();  // 根据下载信息创建每个下载线程,并且启动他们。  for (int i = 0; i < posAndLength.length; i++) {  int pos = posAndLength[i][0];  int length = posAndLength[i][1];  DownloadThread downloadThread = new DownloadThread(i + 1, length,  pos, savePath, urlFile);  new Thread(downloadThread).start();  downloadList.add(downloadThread);  }  }    /**  * 获得文件大小  *   * @return 文件大小  */  public long getFileLength() {  System.out.println("获得文件大小 start......");  HttpURLConnection conn = null;  long result = 0;  try {  URL url = new URL(urlFile);  conn = (HttpURLConnection) url.openConnection();  // 使用Content-Length头信息获得文件大小  result = Long.parseLong(conn.getHeaderField("Content-Length"));  } catch (MalformedURLException e) {  e.printStackTrace();  } catch (IOException e) {  e.printStackTrace();  } finally {  if (conn != null) {  conn.disconnect();  }  }  System.out.println("获得文件大小 end......" + result);  return result;  }    // 具体细节求出每个线程的开始位置和文件下载大小  public int[][] getPosAndLength() {  int[][] result = new int[threadNum][2];  int fileLength = (int) getFileLength();  int every = fileLength % threadNum == 0 ? fileLength / threadNum  : fileLength / threadNum + 1;  for (int i = 0; i < result.length; i++) {  int length = 0;  if (i != result.length - 1) {  length = every;  } else {  length = fileLength - i * every;  }  result[i][0] = i * every;  result[i][1] = length;  }  return result;  }    // 合并文件  public void mergeFiles() {  System.out.println("合并文件 start......");  OutputStream out = null;  try {  out = new FileOutputStream(savePath);  for (int i = 1; i <= threadNum; i++) {  InputStream in = new FileInputStream(savePath + i);  byte[] bytes = new byte[2048];  int read = 0;  while ((read = in.read(bytes)) != -1) {  out.write(bytes, 0, read);  out.flush();  }  if (in != null) {  in.close();  new File(savePath + i).delete();  }  }  } catch (Exception e) {  e.printStackTrace();  } finally {  if (out != null) {  try {  out.close();  } catch (IOException e) {  e.printStackTrace();  }  }  }  System.out.println("合并文件 end......");  }    public String getSavePath() {  return savePath;  }    public void setSavePath(String savePath) {  this.savePath = savePath;  }    public int getThreadNum() {  return threadNum;  }    public void setThreadNum(int threadNum) {  this.threadNum = threadNum;  }    public String getUrlFile() {  return urlFile;  }    public void setUrlFile(String urlFile) {  this.urlFile = urlFile;  }    public boolean isStarted() {  return isStarted;  }    public void setStarted(boolean isStarted) {  this.isStarted = isStarted;  }    public List<DownloadThread> getDownloadList() {  return downloadList;  }    public void setDownloadList(List<DownloadThread> downloadList) {  this.downloadList = downloadList;  } }

 2、DownloadThread类

import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL;   public class DownloadThread implements Runnable {  // 当前第几个线程 , 用于给下载文件起名 file1 file2 file3 ...  private int whichThread;  // 监听单一线程下载是否完成  private boolean isFinish;  // 本线程要下载的文件字节数  private int length;  // 本线程向服务器发送请求时输入流的首位置  private int startPosition;  // 保存的路径  private String savePath;  // 要下载的文件 , 用于创建连接  private String url;    public void run() {  HttpURLConnection conn = null;  InputStream in = null;  OutputStream out = null;  try {  System.out.println("正在执行的线程:" + whichThread);  URL fileUrl = new URL(url);  // 与服务器创建连接  conn = (HttpURLConnection) fileUrl.openConnection();  // 下载使用get请求  conn.setRequestMethod("GET");  // 告诉服务器 , 我是火狐 , 不要不让我下载。  conn.setRequestProperty(  "User-Agent",  "Firefox Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3");  // 这里是设置文件输入流的首位置  conn.setRequestProperty("Range", "bytes=" + startPosition + "-");  // 与服务器创建连接  conn.connect();  // 获得输入流  in = conn.getInputStream();  // 在硬盘上创建file1 , file2 , ...这样的文件 , 准备往里面写东西  out = new FileOutputStream(savePath + whichThread);  // 用于写入的字节数组  byte[] bytes = new byte[4096];  // 一共下载了多少字节  int count = 0;  // 单次读取的字节数  int read = 0;  while ((read = in.read(bytes)) != -1) {  // 检查一下是不是下载到了本线程需要的长度  if (length - count < bytes.length) {  // 比如说本线程还需要900字节,但是已经读取1000  // 字节,则用要本线程总下载长度减去  // 已经下载的长度  read = length - count;  }  // 将准确的字节写入输出流  out.write(bytes, 0, read);  // 已经下载的字节数加上本次循环字节数  count = count + read;  // 如果下载字节达到本线程所需要字节数,消除循环,  // 停止下载  if (count == length) {  break;  }  }  // 将监视变量设置为true  isFinish = true;  } catch (Exception e) {  e.printStackTrace();  } finally {  // 最后进行输入、输出、连接的关闭  if (in != null) {  try {  in.close();  } catch (IOException e) {  e.printStackTrace();  }  }  if (out != null) {  try {  out.close();  } catch (IOException e) {  e.printStackTrace();  }  }  if (conn != null) {  conn.disconnect();  }  }  }    public int getStartPosition() {  return startPosition;  }    public void setStartPosition(int startPosition) {  this.startPosition = startPosition;  }    public String getUrl() {  return url;  }    public void setUrl(String url) {  this.url = url;  }    public int getWhichThread() {  return whichThread;  }    public void setWhichThread(int whichThread) {  this.whichThread = whichThread;  }    public int getLength() {  return length;  }    public void setLength(int length) {  this.length = length;  }    public String getSavePath() {  return savePath;  }    public void setSavePath(String savePath) {  this.savePath = savePath;  }    public DownloadThread(int whichThread, int length, int startPosition,  String savePath, String url) {  super();  this.whichThread = whichThread;  this.length = length;  this.startPosition = startPosition;  this.savePath = savePath;  this.url = url;  }    public DownloadThread() {  super();  }    public boolean isFinish() {  return isFinish;  }    public void setFinish(boolean isFinish) {  this.isFinish = isFinish;  } }

3、TestDownload测试类

public class TestDownload {    public static void main(String[] args) {  DownloadManager downloadManager = new DownloadManager("d:/upload/09018417.zip" , 5 , "http://10.1.2.65:8080/cetvossFront/09018417.zip");  downloadManager.action();  } }

关于怎么在java中利用多线程实现文件下载问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI