验证中...
片段 1 片段 2 片段 3 片段 4 片段 5 片段 6 片段 7
Java多线程下载文件和断点下载
原始数据 复制代码
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.print.attribute.standard.Finishings;
public class MultiDownload {
static int ThreadCount = 3; //代表3个进程
static int finishedThread = 0; //记录文件下完的数字
//确定下载地址
static String path = "http://192.168.13.13:8080/QQPlayer.exe";
public static void main(String[] args) {
//发送get请求,请求这个地址的资源
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
if(conn.getResponseCode() == 200){
//拿到所请求资源文件的长度
int length = conn.getContentLength();
File file = new File("QQPlayer.exe");
//生成临时文件
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
//设置临时文件的大小
raf.setLength(length);
raf.close();
//计算出每个线程应该下载多少字节
int size = length / ThreadCount;
for (int i = 0; i < ThreadCount; i++) {
//计算线程下载的开始位置和结束位置
int startIndex = i * size;
int endIndex = (i + 1) * size - 1;
//如果是最后一个线程,那么结束位置写死
if(i == ThreadCount - 1){
endIndex = length - 1;
}
// System.out.println("线程" + i + "的下载区间是:" + startIndex + "---" + endIndex);
new DownLoadThread(startIndex, endIndex, i).start();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class DownLoadThread extends Thread{
int startIndex;
int endIndex;
int threadId;
public DownLoadThread(int startIndex, int endIndex, int threadId) {
super();
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run() {
//再次发送http请求,下载原文件
try {
File progressFile = new File(threadId + ".txt");
//判断进度临时文件是否存在
if(progressFile.exists()){
FileInputStream fis = new FileInputStream(progressFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
//从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
startIndex += Integer.parseInt(br.readLine());
fis.close();
}
System.out.println("线程" + threadId + "的下载区间是:" + startIndex + "---" + endIndex);
HttpURLConnection conn;
URL url = new URL(MultiDownload.path);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//设置本次http请求所请求的数据的区间
conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
//请求部分数据,相应码是206
if(conn.getResponseCode() == 206){
//流里此时只有1/3原文件的数据
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
int total = 0;
//拿到临时文件的输出流
File file = new File("QQPlayer.exe");
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
//把文件的写入位置移动至startIndex
raf.seek(startIndex);
while((len = is.read(b)) != -1){
//每次读取流里数据之后,同步把数据写入临时文件
raf.write(b, 0, len);
total += len;
// System.out.println("线程" + threadId + "下载了" + total);
//生成一个专门用来记录下载进度的临时文件
RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
//每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
progressRaf.write((total + "").getBytes());
progressRaf.close();
}
System.out.println("线程" + threadId + "下载完毕-------------------OK!");
raf.close();
//把记录进程的文件删除 必须3个进程全部都下载完成后才可以删除
MultiDownload.finishedThread++;
synchronized (MultiDownload.path) { //有线程安全问题,静态变量为唯一的
if(MultiDownload.finishedThread == MultiDownload.ThreadCount){
for (int i = 0; i < MultiDownload.ThreadCount; i++) {
File f = new File(i + ".txt");
f.delete();
}
MultiDownload.finishedThread = 0;
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
网络资源的单线程下载
原始数据 复制代码
package com.wsq.utils.download.demo01;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
/**
* @Author wsq
* @Package com.wsq.utils.download
* @Description: 网络资源的单线程下载
* @Date Created by wsq on 2017/12/31上午12:41.
* @Modified By:
*/
@SuppressWarnings("serial")
public class SingleThreadDownloadFrame extends JFrame {
private JTextField tf_address;
/**
* Launch the application
*
* @param args
*/
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SingleThreadDownloadFrame frame = new SingleThreadDownloadFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame
*/
public SingleThreadDownloadFrame() {
super();
getContentPane().setLayout(null);
setTitle("网络资源的单线程下载");
setBounds(100, 100, 500, 237);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel label = new JLabel();
label.setText("网络资源的网址:");
label.setBounds(10, 88, 118, 18);
getContentPane().add(label);
tf_address = new JTextField();
tf_address.setBounds(117, 86, 357, 22);
getContentPane().add(tf_address);
final JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
String address = tf_address.getText().trim();// 获得网址
download(address); // 下载文件
}
});
button.setText("单击开始下载");
button.setBounds(41, 144, 145, 28);
getContentPane().add(button);
final JButton button_1 = new JButton();
button_1.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
tf_address.setText(null);// 清除文本框内容
tf_address.requestFocus();// 文本框获得焦点
}
});
button_1.setText("清 空");
button_1.setBounds(204, 144, 106, 28);
getContentPane().add(button_1);
final JButton button_2 = new JButton();
button_2.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
button_2.setText("退 出");
button_2.setBounds(328, 144, 106, 28);
getContentPane().add(button_2);
final JLabel label_1 = new JLabel();
label_1.setForeground(new Color(0, 0, 255));
label_1.setFont(new Font("", Font.BOLD, 24));
label_1.setText("网络资源的单线程下载");
label_1.setBounds(117, 21, 301, 48);
getContentPane().add(label_1);
}
public void download(String urlAddr) { // 从指定网址下载文件
try {
URL url = new URL(urlAddr); // 创建URL对象
URLConnection urlConn = url.openConnection(); // 获得连接对象
urlConn.connect(); // 打开到url引用资源的通信链接
InputStream in = urlConn.getInputStream(); // 获得输入流对象
String filePath = url.getFile(); // 获得完整路径
int pos = filePath.lastIndexOf("/"); // 获得路径中最后一个斜杠的位置
String fileName = filePath.substring(pos + 1); // 截取文件名
// FileOutputStream out = new FileOutputStream("C:/"+fileName); // 创建输出流对象
FileOutputStream out = new FileOutputStream("/Users/able/Desktop/" + fileName); // 创建输出流对象
byte[] bytes = new byte[1024]; // 声明存放下载内容的字节数组
int len = in.read(bytes); // 从输入流中读取内容
while (len != -1) {
out.write(bytes, 0, len); // 将读取的内容写到输出流
len = in.read(bytes); // 继续从输入流中读取内容
}
out.close(); // 关闭输出流
in.close(); // 关闭输入流
JOptionPane.showMessageDialog(null, "下载完毕");
} catch (Exception e) {
e.printStackTrace();
}
}
}
网络资源的单线程下载.png
网络资源的多线程下载(注意:如下代码是两个类)
原始数据 复制代码
类1:
package com.wsq.utils.download.demo02;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
/**
* @Author wsq
* @Package com.wsq.utils.download
* @Description: 网络资源的多线程下载,主方法
* @Date Created by wsq on 2017/12/31上午12:41.
* @Modified By:
*/
@SuppressWarnings("serial")
public class MultiThreadDownFrame extends JFrame {
private JTextField tf_address;
/**
* Launch the application
*
* @param args
*/
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MultiThreadDownFrame frame = new MultiThreadDownFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MultiThreadDownFrame() {
super();
getContentPane().setLayout(null);
setTitle("网络资源的多线程下载");
setBounds(100, 100, 482, 189);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JButton button = new JButton();
button.setBounds(10, 95, 106, 28);
getContentPane().add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
try {
String address = tf_address.getText();// 获得网络资源地址
download(address, "/Users/able/Desktop/apache-maven-3.5.2-bin.tar.gz", 100);// 调用download()方法,将下载的网络资源保存到磁盘
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
button.setText("下 载");
final JLabel label = new JLabel();
label.setText("网络资源的地址:");
label.setBounds(10, 44, 106, 18);
getContentPane().add(label);
tf_address = new JTextField();
tf_address.setBounds(114, 42, 341, 22);
getContentPane().add(tf_address);
final JButton button_1 = new JButton();
button_1.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
tf_address.setText(null);
}
});
button_1.setText("清 空");
button_1.setBounds(179, 95, 106, 28);
getContentPane().add(button_1);
final JButton button_2 = new JButton();
button_2.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
button_2.setText("退 出");
button_2.setBounds(349, 95, 106, 28);
getContentPane().add(button_2);
}
public void download(String url, String dest, int threadNum) throws Exception {
URL downURL = new URL(url);// 创建网络资源的URL
HttpURLConnection conn = (HttpURLConnection) downURL.openConnection();// 打开网络边接
long fileLength = -1;// 用于存储文件长度的变量
int stateFlagCode = conn.getResponseCode();// 获得连接状态标记代码
if (stateFlagCode == 200) {// 网络连接正常
fileLength = conn.getContentLength();// 获得文件的长度
conn.disconnect();// 取消网络连接
}
if (fileLength > 0) {
System.out.println("下载启用的线程数threadNum:" + threadNum);
long byteCounts = fileLength / threadNum + 1;// 计算每个线程的字节数
File file = new File(dest);// 创建目标文件的File对象
int i = 0;
while (i < threadNum) {
long startPosition = byteCounts * i;// 定义开始位置
long endPosition = byteCounts * (i + 1);// 定义结束位置
if (i == threadNum - 1) {
DownMultiThread fileThread = new DownMultiThread(url, file, startPosition, 0);// 创建DownMultiThread线程的实例
new Thread(fileThread).start();// 启动线程对象
} else {
DownMultiThread fileThread = new DownMultiThread(url, file, startPosition, endPosition);// 创建DownMultiThread线程的实例
new Thread(fileThread).start();// 启动线程对象
}
i++;
}
JOptionPane.showMessageDialog(null, "完成网络资源的下载。");
}
}
}
类2:
package com.wsq.utils.download.demo02;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JOptionPane;
/**
* @Author wsq
* @Package com.wsq.utils.download
* @Description: 网络资源的多线程下载
* @Date Created by wsq on 2017/12/31上午12:41.
* @Modified By:
*/
public class DownMultiThread implements Runnable {
private String sUrl = "";// 网络资源地址
private File desFile;// 需要写入的目标文件对象
private long startPos;// 写入的开始位置
private long endPos;// 写入的结束位置
/**
* @param sUrl 网络资源地址
* @param desFile 需要写入的目标文件对象
* @param startPos 写入的开始位置
* @param endPos 写入的结束位置
*/
public DownMultiThread(String sUrl, File desFile, long startPos, long endPos) {
this.sUrl = sUrl;
this.desFile = desFile;
this.startPos = startPos;
this.endPos = endPos;
}
public void run() {
try {
URL url = new URL(sUrl);// 创建下载资源的URL对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 打开连接对象
conn.setRequestProperty("User-Agent", "NetFox");// 设置请求属性
String rangeProperty = "bytes=" + startPos + "-";// 定义范围属性
if (endPos > 0) {
rangeProperty = "bytes=" + startPos + "-" + endPos;// 调整范围属性的值
}
conn.setRequestProperty("RANGE", rangeProperty);// 指定范围属性
RandomAccessFile out = new RandomAccessFile(desFile, "rw");// 创建可读写的流对象
out.seek(startPos);// 指定读写的开始标记
InputStream in = conn.getInputStream();// 获得网络资源的输入流对象
BufferedInputStream bin = new BufferedInputStream(in);// 创建输入缓冲流对象
byte[] buff = new byte[2048];// 创建字节数组
int len = -1;// 声明存放读取字节数的变量
len = bin.read(buff);// 读取到内容并添加到字节数组
while (len != -1) {
out.write(buff, 0, len);// 写入磁盘文件
len = bin.read(buff);// 读取到内容并添加到字节数组
}
out.close();// 关闭流
bin.close();// 关闭流
conn.disconnect();// 断开连接
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
}
}
}
网络资源的多线程下载.png
下载网络资源的断点续传
原始数据 复制代码
package com.wsq.utils.download.demo03;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
/**
* @Author wsq
* @Package com.wsq.utils.download
* @Description: 下载网络资源的断点续传
* @Date Created by wsq on 2017/12/31上午12:41.
* @Modified By:
*/
@SuppressWarnings("serial")
public class BreakPointSuperveneFrame extends JFrame {
private JTextField tf_totalLength;
private JTextField tf_residuaryLength;
private JTextField tf_readToPos;
private JTextField tf_address;
private JTextField tf_endPos;
private JTextField tf_startPos;
private String urlAddress = "";// 用于存储网络资源的地址
private long totalLength = 0;// 存储网络资源的大小,以字节为单位
private long readToPos = 0;// 存储上次读取到的位置
private long residuaryLength = 0;// 存储未读内容的大小
/**
* Launch the application
*
* @param args
*/
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BreakPointSuperveneFrame frame = new BreakPointSuperveneFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame
*/
public BreakPointSuperveneFrame() {
super();
getContentPane().setLayout(null);
setTitle("下载网络资源的断点续传");
setBounds(100, 100, 514, 238);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tf_startPos = new JTextField();
tf_startPos.setBounds(80, 165, 113, 22);
getContentPane().add(tf_startPos);
final JLabel label = new JLabel();
label.setText("起始位置:");
label.setBounds(10, 167, 74, 18);
getContentPane().add(label);
final JLabel label_1 = new JLabel();
label_1.setText("结束位置:");
label_1.setBounds(199, 167, 74, 18);
getContentPane().add(label_1);
tf_endPos = new JTextField();
tf_endPos.setBounds(267, 165, 117, 22);
getContentPane().add(tf_endPos);
final JLabel label_2 = new JLabel();
label_2.setText("网络资源的地址:");
label_2.setBounds(10, 52, 113, 18);
getContentPane().add(label_2);
tf_address = new JTextField();
tf_address.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
try {
urlAddress = tf_address.getText().trim();
URL url = new URL(urlAddress);// 获得网络资源的URL
HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 获得连接对象
connection.connect();// 连接网络资源
totalLength = connection.getContentLength();// 获得网络资源的长度
connection.disconnect();// 断开连接
tf_totalLength.setText(String.valueOf(totalLength));// 显示总长度
tf_readToPos.setText("0");// 显示上次读取到的位置
residuaryLength = totalLength;// 未读内容为文件总长度
tf_residuaryLength.setText(String.valueOf(residuaryLength));// 显示未读内容
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
}
});
tf_address.setBounds(119, 50, 365, 22);
getContentPane().add(tf_address);
final JLabel label_3 = new JLabel();
label_3.setForeground(new Color(0, 0, 255));
label_3.setFont(new Font("", Font.BOLD, 14));
label_3.setText("输入网络资源的地址并回车,可以获得网络资源的大小。");
label_3.setBounds(10, 10, 384, 22);
getContentPane().add(label_3);
final JLabel label_4 = new JLabel();
label_4.setForeground(new Color(128, 0, 0));
label_4.setText("网络资源的大小为");
label_4.setBounds(10, 76, 113, 38);
getContentPane().add(label_4);
final JLabel label_5 = new JLabel();
label_5.setText("上次读取到");
label_5.setBounds(10, 123, 74, 18);
getContentPane().add(label_5);
tf_readToPos = new JTextField();
tf_readToPos.setBounds(80, 121, 113, 22);
tf_readToPos.setEnabled(false);
getContentPane().add(tf_readToPos);
final JLabel label_6 = new JLabel();
label_6.setText("字节处,还剩");
label_6.setBounds(202, 123, 87, 18);
getContentPane().add(label_6);
tf_residuaryLength = new JTextField();
tf_residuaryLength.setBounds(285, 120, 117, 22);
tf_residuaryLength.setEnabled(false);
getContentPane().add(tf_residuaryLength);
final JLabel label_7 = new JLabel();
label_7.setText("字节未读。");
label_7.setBounds(404, 123, 80, 18);
getContentPane().add(label_7);
final JLabel label_4_1 = new JLabel();
label_4_1.setForeground(new Color(128, 0, 0));
label_4_1.setText("个字节。");
label_4_1.setBounds(404, 76, 80, 38);
getContentPane().add(label_4_1);
tf_totalLength = new JTextField();
tf_totalLength.setBounds(119, 84, 283, 22);
tf_totalLength.setEnabled(false);
getContentPane().add(tf_totalLength);
final JButton button = new JButton();
button.setBounds(395, 162, 89, 28);
getContentPane().add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
if (totalLength == 0) {
JOptionPane.showMessageDialog(null, "没有网络资源。\n\n请输入正确的网址,然后回车。");
return;
}
long startPos = 0;// 起始位置
long endPos = 0;// 结束位置
try {
startPos = Long.parseLong(tf_startPos.getText().trim());// 起始位置
endPos = Long.parseLong(tf_endPos.getText().trim());// 结束位置
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "输入的起始位置或结束位置不正确。");
return;
}
readToPos = endPos;// 记录读取到的位置
residuaryLength = totalLength - readToPos;// 记录未读内容的大小
tf_readToPos.setText(String.valueOf(readToPos));// 显示读取到的位置
tf_residuaryLength.setText(String.valueOf(residuaryLength));// 显示未读字节数
tf_startPos.setText(String.valueOf(readToPos));// 设置下一个读取点的开始位置
tf_endPos.setText(String.valueOf(totalLength));// 设置下一个读取点的结束位置
tf_endPos.requestFocus();// 使结束位置文本框获得焦点
tf_endPos.selectAll();// 选择结束位置文本框中的全部内容,方便输入结束位置值
download(startPos, endPos);// 调用方法进行下载
}
});
button.setText("开始下载");
}
public void download(long startPosition, long endPosition) {
try {
URL url = new URL(urlAddress);// 获得网络资源的URL
HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 获得连接对象
connection.setRequestProperty("User-Agent", "NetFox");// 设置请求属性
String rangeProperty = "bytes=" + startPosition + "-";// 定义请求范围属性
if (endPosition > 0) {
rangeProperty += endPosition;// 调整请求范围属性
}
connection.setRequestProperty("RANGE", rangeProperty);// 设置请求范围属性
connection.connect();// 连接网络资源
InputStream in = connection.getInputStream();// 获得输入流对象
String file = url.getFile();// 获得文件对象
String name = file.substring(file.lastIndexOf('/') + 1);// 获得文件名
FileOutputStream out = new FileOutputStream("/Users/able/Desktop/" + name, true);// 创建输出流对象,保存下载的资源
byte[] buff = new byte[2048];// 创建字节数组
int len = 0;// 定义存储读取内容长度的变量
len = in.read(buff);// 读取内容
while (len != -1) {
out.write(buff, 0, len);// 写入磁盘
len = in.read(buff);// 读取内容
}
out.close();// 关闭流
in.close();// 关闭流
connection.disconnect();// 断开连接
if (readToPos > 0 && readToPos == totalLength) {
JOptionPane.showMessageDialog(null, "完成网络资源的下载。\n单击“确定”按钮退出程序。");
System.exit(0);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
下载网络资源的断点续传.png

评论列表( 2 )

cherishpf 2017-12-29 17:01

请问,下载完成后,下载好的文件在哪里?不用写目标目录吗?

1305317_wsqcode
wenshaocode 2017-12-30 00:30

您好,文件下载路径默认在项目根目录下,如果想要修改的话可以自定义位置,例如: File file = new File("/Users/able/Desktop/apache-maven-3.0.5-bin.tar.gz");

你可以在登录后,发表评论

8_float_left_people 8_float_left_close