这个小程序运用java的多线程技术,并发的下载一个文件,代码如下:
一、FileSplit.java
import javax.swing.JTextArea;//引入类
import java.net.*;
import java.io.*;
public class FileSplit extends Thread {
String downloadURL;// 下载文件的地址
long startPosition;//线程的开始位置
long endPosition;//线程的结束位置
int threadID;
JTextArea textArea = new JTextArea();//创建文本域
boolean isDone = false;//是否下载完毕
RandomAccessFile random;
public FileSplit(String downloadURL, String saveAs, long nStart, long nEnd,
int id, JTextArea textArea) {
this.downloadURL = downloadURL;
this.startPosition = nStart;
this.endPosition = nEnd;
this.threadID = id;
this.textArea = textArea;
try {
random = new RandomAccessFile(saveAs, "rw");//创建随机访问对象,以读/写方式
random.seek(startPosition);//定位文件指针到startPosition位置
} catch (Exception e) {//捕获异常
System.out.println("创建随机访问对象出错:"+e.getMessage());
}
}
public void run() {//实现Thread类的方法
try {
URL url = new URL(downloadURL);// 根据网址创建URL对象
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();//创建远程对象连接对象
String sProperty = "bytes=" + startPosition + "-";
httpConnection.setRequestProperty("RANGE", sProperty);
textArea.append("\n 线程" + threadID + "下载文件! 请等待...");
InputStream input = httpConnection.getInputStream();//获得输入流对象
byte[] buf = new byte[1024];//创建字节数据存储文件的数据
int splitSpace;
splitSpace = (int) endPosition - (int) startPosition;//获得每个线程的间隔
if (splitSpace > 1024)
splitSpace = 1024;
while (input.read(buf, 0, splitSpace) > 0 && startPosition < endPosition) {//读取文件信息
splitSpace = (int) endPosition - (int) startPosition;
if (splitSpace > 1024)
splitSpace = 1024;
textArea.append("\n线程: " + threadID + " 开始位置: "
+ startPosition + ", 间隔长度: " + splitSpace);
random.write(buf, 0, splitSpace);//写入文件
startPosition += splitSpace;//开始位置改变
}
textArea.append("\n 线程" + threadID + "下载完毕!!");
random.close();//释放资源
input.close();
isDone = true;
} catch (Exception e) {//捕获异常
System.out.println("多线程下载文件出错:"+e.getMessage());
}
}
}
二、DownLoadFile.java
import javax.swing.JTextArea;//引入类
import java.net.*;
public class DownLoadFile extends Thread {//分析下载的文件并启动下载进程
String downloadURL;//下载文件的地址
String saveFileAs;//文件另存为
int threadCount;//线程总数
String log = new String();//下载过程的日志记录
JTextArea textArea = new JTextArea();//创建文本域
long[] position;
long[] startPosition;//每个线程开始位置
long[] endPosition;//每个线程结束位置
FileSplit[] FileSplitt; // 子线程对象
long fileLength;//下载的文件的长度
public DownLoadFile(String downloadURL, String saveFileAs, int threadCount,
JTextArea textArea){//构造方法进行初始化
this.downloadURL = downloadURL;
this.saveFileAs = saveFileAs;
this.threadCount = threadCount;
this.textArea = textArea;
startPosition = new long[threadCount];
endPosition = new long[threadCount];
}
public void run() {//实现Thread类的方法
log = "目标文件: " + downloadURL;
textArea.append("\n" + log);//日志写入文本域
log = "\n 线程总数: " + threadCount;
textArea.append("\n" + log);
try {
fileLength = getFileSize();//获得文件长度
if (fileLength == -1) {//不可获取文件长度或没有找到资源
textArea.append("\n 不可知的文件长度!请重试!!");
} else {
if (fileLength == -2) {//无法获取文件或没有找到资源
textArea.append("\n 文件无法获取,没有找到指定资源,请重试!!");
} else {
for (int i = 0; i < startPosition.length; i++) {//循环对每个线程的开始位置赋值
startPosition[i] = (long) (i * (fileLength / startPosition.length));
}
for (int i = 0; i < endPosition.length - 1; i++)//循环对每个线程的结束位置赋值
endPosition[i] = startPosition[i + 1];
endPosition[endPosition.length - 1] = fileLength;//最后一个线程的结束位置是文件的长度
for (int i = 0; i < startPosition.length; i++) {//循环显示每个线程的开始和结束位置
log = "线程:" + i + "下载范围:" + startPosition[i] + "--"
+ endPosition[i];
textArea.append("\n" + log);
}
FileSplitt = new FileSplit[startPosition.length];
for (int i = 0; i < startPosition.length; i++) {//启动一组子线程
FileSplitt[i] = new FileSplit(downloadURL, saveFileAs,
startPosition[i], endPosition[i], i, textArea);
log = "线程 " + i + "启动";
textArea.append("\n" + log);
FileSplitt[i].start();//启动线程
}
boolean breakWhile = true;
while (breakWhile) {//当条件始终为true时进行循环
Thread.sleep(500);//线程休眠
breakWhile = false;
for (int i = 0; i < FileSplitt.length; i++) {
if (!FileSplitt[i].isDone) {//循环判断每个线程是否结束
breakWhile = true;
break;
}
}
}
textArea.append("\n 文件传输结束!");// 文件传输结束
}
}
} catch (Exception ex) {//捕获异常
ex.printStackTrace();
}
}
public long getFileSize() {//获得文件的长度的方法
int fileLength = -1;
try {
URL url = new URL(downloadURL);//根据网址创建URL对象
HttpURLConnection httpConnection = (HttpURLConnection) (url
.openConnection());//创建远程对象连接对象
int responseCode = httpConnection.getResponseCode();
if (responseCode >= 400) {//没有获得响应信息
System.out.println("Web服务器响应错误");
return -2;// Web服务器响应错误
}
String sHeader;
for (int i = 1;; i++)
{ //查找标识文件长度的文件头,获取文件长度
sHeader = httpConnection.getHeaderFieldKey(i);
if (sHeader != null) {
if (sHeader.equals("Content-Length")) {//查找标识文件长度的文件头
fileLength = Integer.parseInt(httpConnection
.getHeaderField(sHeader));
break;
}
} else {
break;
}
}
} catch (Exception e) {//捕获异常
System.out.println("无法获得文件长度:"+e.getMessage());
}
return fileLength;
}
}
三、TextXunleiFrame.java
import javax.swing.*;//引入类
import java.awt.*;
import java.awt.event.*;
public class TextXunleiFrame extends JFrame {// 模拟迅雷下载的界面面板
private JPanel contentPane;// 迅雷面板
private JTextField webField = new JTextField();// 下载地址的文本框
private JTextField localFile = new JTextField();// 下载到本地的文本框
private JButton button = new JButton();// 下载按钮
private JLabel webLabel = new JLabel();// 目标标签
private JLabel localLabel = new JLabel();// 下载到本地标签
private JTextArea textArea = new JTextArea();// 显示下载记录的文本域
private String downloadURL = new String();// 下载地址
private String saveFileAs = new String();// 另存为
public TextXunleiFrame() {// 构造方法进行初始化
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
toInit();// 调用方法初始化面板
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void toInit() throws Exception {//初始化面板
contentPane = (JPanel) this.getContentPane();//创建面板
contentPane.setLayout(null);//没有设置面板布局
this.setSize(new Dimension(380, 320));//面板的大小
this.setLocation(100, 100);//面板位置
this.setTitle("仿迅雷多线程下载");//面板标题
webField.setBounds(new Rectangle(150, 200, 200, 20));//设置文本框的位置
//设置默认下载路径
webField.setText("http://localhost/test/test.txt");
localFile.setBounds(new Rectangle(150, 240, 120, 20));//设置文本框的位置
localFile.setText("d:\\try.rar");//设置默认另存为
webLabel.setBounds(new Rectangle(20, 200, 120, 20));//标签的位置
webLabel.setText("下载的目标文件为: ");
localLabel.setBounds(new Rectangle(20, 240, 120, 20));//标签的位置
localLabel.setText("下载的文件另存为: ");
button.setBounds(new Rectangle(280, 240, 60, 20));//按钮的位置
button.setText("下载");
button.addActionListener(new ActionListener() {//按钮添加监听事件
public void actionPerformed(ActionEvent e) {
button_actionPerformed(e);//调用事件
}
});
JScrollPane scrollPane = new JScrollPane(textArea);//创建有滑动条的面板将文本域放在上面
scrollPane.setBounds(new Rectangle(20, 20, 330, 170));//面板的位置
textArea.setEditable(false);//不可编辑
contentPane.add(webField, null);//将文本框添加到面板中
contentPane.add(localFile, null);//将文本框添加到面板中
contentPane.add(webLabel, null);//将标签添加到面板中
contentPane.add(localLabel, null);//将标签添加到面板中
contentPane.add(button, null);//将按钮添加到面板中
contentPane.add(scrollPane, null);//将滑动条添加到面板中
downloadURL = webField.getText();//获得文本框中的文本
saveFileAs = localFile.getText();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);//设置默认关闭操作
}
public void button_actionPerformed(ActionEvent e) {//点击事件触发方法,启动分析下载文件的进程
downloadURL = webField.getText();//获得目标文件的网址
saveFileAs = localFile.getText();//获得另存为的地址
if (downloadURL.compareTo("") == 0)
textArea.setText("请输入要下载的文件完整地址");
else if(saveFileAs.compareTo("") == 0) {
textArea.setText("请输入保存文件完整地址");
}else {
try {
DownLoadFile downFile = new DownLoadFile(downloadURL,
saveFileAs, 5, textArea);//传入参数实例化下载文件对象
downFile.start();//启动下载文件的线程
textArea.append("主线程启动...");
} catch (Exception ec) {//捕获异常
System.out.println("下载文件出错:"+ec.getMessage());
}
}
}
public static void main(String[] args) {//java程序主入口处
TextXunleiFrame frame=new TextXunleiFrame();//实例化对象进行初始化
frame.setVisible(true);//设置窗口可视
}
}