大二末了,选好了方向,而去也喜欢网络并发,多线程之类的,就决定做个多线程下载器,学习学习文件,网络,线程间通讯的方法。
代码其实早就开始写,只是一直比较忙,也没写多少。今天认真花了一天把下载线程写了。
这个主要问题是下载文件的配置信息的写入,刚开始没有计算好seek()的参数,两个数之间总是差一截空白,找一两个点,发现seek是字节,而且JAVA写入的字母数字都是2字节一个的。下面是下载线程的代码。pause是传进去的参数,控制暂停的,暂停实际上就是停止此线程。
最近一直在忙着另一个比赛,没有时间完善,先把做好的部分代码贴上来吧,目前的主要问题就是断点续传那个文件总是写出错。
package downloadThread;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
/*import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;//udp
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;//tcp
*/
public class DownloadBlock implements Runnable {
/**
* 下载需要的信息。
*/
private long begin= 0 ;
private long end= 0 ;
private int threadID= 0 ;
private String filePath;
/**
* 下载状态。
*/
private URL url;
//缓存空间
private final int BUFFER_SIZE = 1024*8;
private long currentPosition= 0 ;
/**
* 下载暂停与否,1表示继续下载,0表示暂停
* */
volatile private Integer pause;
//Http连接
HttpURLConnection conn = null;
//从Http处获得输入流
InputStream in = null;
//目标文件
RandomAccessFile accessFile = null;
//下载文件配置信息,前1kb存放链接,
RandomAccessFile cfg = null;
//构造函数的所有参数应该已经被验证过
public DownloadBlock(URL url, long begin, long end, String filePath,
int threadID,Integer pause) {
super();
this.url = url;
this.begin = begin;
this.end = end;
this.filePath = filePath;
this.threadID = threadID;
this.pause = pause;
}
/*private String getFileExtName(String path) {
return path.substring(path.lastIndexOf("."));
} */
public void run() {
currentPosition= 0 ;
//NIO模式下的UDP实现暂停
/*InetSocketAddress socketAddress = new InetSocketAddress(port);//没有指名ip表示是本机
DatagramChannel server = null; //udp类型
ByteBuffer buf = ByteBuffer.allocate(10);//接受命令缓冲区
*/ try {
//Selector select = Selector.open();
//变量赋值
final File file = new File(filePath);
final File fileCFG = new File(filePath+".cfg");
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(2000);// 请求超时时间
conn.setRequestMethod("GET");
// TODO Auto-generated method stub
conn.setRequestProperty("Range", "bytes=" + begin
+ "-" + end + "");// 设置一般请求属性 范围
//网络输入准备
in = conn.getInputStream();
byte[] data = new byte[BUFFER_SIZE];
int len = 0;
accessFile = new RandomAccessFile(file, "rwd");
//跳过指定《字节》
accessFile.seek(begin);
cfg = new RandomAccessFile(fileCFG, "rwd");
// 链接 + MD5 + 线程数 + 每个线程负责下载的最后一个块 +每个线程的当前块
cfg.seek((1024+64+64+64*2*threadID)*2);//每个信息64字节,并在下载时写入
//记录下此线程的最后一个块
cfg.writeChars(iTochars(end, 64));
while (pause.intValue()==1&&(len = in.read(data)) != -1) {
accessFile.write(data, 0, len);
currentPosition += len;
//记录下此线程当前的下载位置,为暂停做准备
cfg.seek((1024+64+64+64*2*threadID + 64)*2);
cfg.writeChars(iTochars(currentPosition, 64));
}
if(currentPosition==end)System.out.println("线程:" + threadID + "下载完成!");
else if(len!=-1)System.out.println("线程"+threadID+"已经暂停");
else System.out.println("线程"+threadID+"出现意外终止");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
accessFile.close();
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private String iTochars(long num,int n){
char a[] = ((new Long(num)).toString()).toCharArray();
char b[] = new char[n];
int l = n - a.length;
int i ,j;
//System.out.println(a);
for(i=0;i<l;i++)
{
b[i]='0';
}
for(j=0;j<a.length;j++)
{
b[j+i] = a[j];
}
return new String(b);
}
public static void main(String[] args)
{
try{
//控制是否暂停的。
Integer pause = new Integer(1);
URL url = new URL("http://download.bloxy.cn/BloxySetup_1.4.3.3.exe");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
DownloadBlock a = new DownloadBlock(url,0,conn.getContentLengthLong(),"C:\\Users\\NSUS\\Desktop\\BloxySetup.exe",1,pause);
Thread t = new Thread(a);
t.start();
}catch(Exception e){
e.printStackTrace();
}
}
}