多线程文件下载

这个小程序运用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);//设置窗口可视
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值