📄 httpdown.java
字号:
/**
* Http下载协议,支持多任务多线程,能自动识别重名的文件,智能地对要下载的重名的文件进行重命名,
* 保证不会对硬盘原先的文件造成损失;本程序还能自动创建多级文件夹,能保证当下载时的保存目录不存在时也能正确下载;
*/
/**
* @author king、dfl
* @version V1.1
*/
import java.net.*;
import java.io.*;
// HTTP下载方式
public class HttpDown
{
public HttpDown(String fileURL, String savePath)
{
this.downFielURL = fileURL; // 可以是任何的文件类型
this.savePath = savePath;
this.ctrlThread = new ControlThread(); // 新建一个控制线程
this.ctrlThread.run();
}
public HttpDown(String fileURL, String savePath,int threadNum)
{
this.downFielURL = fileURL; // 可以是任何的文件类型
this.savePath = savePath;
this.downThreadNum = threadNum;
this.ctrlThread = new ControlThread(); // 新建一个控制线程
this.ctrlThread.run();
}
private class DownThread extends Thread // 数据下载的线程
{
private long start; // 每个下载线程对象开始下载的起始位置
private long end; // 每个下载线程对象下载结束时的 文件位置
private boolean stop = false; // 该线程对象是否暂停
private int tryTimes = 20; // 尝试连接的次数 假如为负数的话说明没有限制
private long readCount = 0;
public DownThread(long offset, long end)
{
this.start = offset;
this.end = end;
}
public void run()
{
int httpStatusCode = 0;// 服务器返回的状态值
// 这里开始向服务器请求数据 将要服务器返回的数据保存到文件
System.out.println(savePath +" in DownThread");
try
{
int readNum;
byte buf[] = new byte[4096];
conn = url.openConnection();
HttpURLConnection httpconn = (HttpURLConnection) conn;
httpconn.setRequestProperty("User-Agent", "NetFox");
System.out.println("~ first " + start + " end " + end);
httpconn.setRequestProperty("RANGE", "bytes=" + start + "-");
httpconn.setRequestProperty("GET", url.getFile() + " HTTP/1.1");
httpconn.setRequestProperty("Accept",
"image/gif,image/x-xbitmap,application/msword,*/*");
httpconn.setRequestProperty("Connection", "Keep-Alive");
//DataInputStream br=new DataInputStream( httpconn.getInputStream());
InputStream inStream = httpconn.getInputStream();
RandomAccessFile rafrw = new RandomAccessFile(savePath, "rw");
rafrw.seek(start);
readNum = inStream.read(buf);
System.out.println("qq " + (end - start + 1));
if (readNum > (int) (end - start + 1))
readNum = (int) (end - start + 1);
while (readCount < (end - start + 1) && readNum != -1)
{
setTotalReadCount(readNum);
readCount = readCount + readNum;
rafrw.write(buf, 0, readNum);
// System.out.println("q"+i);
readNum = inStream.read(buf);
if (readCount > (int) (end - start + 1)) /////////// 这是什么?
readCount = (int) (end - start + 1);
}
if(totalReadNum < fileLen) // 测试用
System.out.println("DownLoad Error. len "+fileLen+" readCount "+readCount);
else
{
hasFinished = true;
}
rafrw.close();
inStream.close();
System.out.println("exit in Download Thread.");
}
catch (IOException e)
{
System.out.println(e);
}
}
public synchronized void setTotalReadCount(long readnum)
{
totalReadNum += readnum;
}
}
private class ControlThread extends Thread //线程控制类
{
public ControlThread()
{
try
{
url = new URL(downFielURL);
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
public void run()
{
// 在这里可以假如是否要增加线程
try
{
conn = url.openConnection();
//conn.connect();
fileLen = conn.getContentLength(); //得到要下载的文件的长度
}
catch (Exception e)
{
e.getMessage();
}
System.out.println(savePath + " 保存路径");
File savefile =new File(savePath);
String parentPath = new String (savefile.getParentFile().toString());// 测试 保存的目录是否存在
System.out.println(parentPath + " parentPath");
File parent = new File(parentPath);
if(!parent.exists()) // 当要保存的文件目录不存在时 创建文件目录
{
System.out.println("文件目录不存在。");
if(parent.mkdirs())
System.out.println(" 创建文件夹成功。");
else
System.out.println(" 创建文件夹失败。");
}
if(!savefile.exists()) // 文件不存在时 创建一个文件
{
System.out.println("文件名没有重复,可以创建该文件。");
try
{
savefile.createNewFile();
}
catch (IOException e)
{
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
// 当所要保存的文件名存在时 在文件名后加上(1)等
else{
int jd_i = 1;
String jd_name;
String jd_savepath;
while(true)
{
jd_name = getOKName(savefile.getName(),jd_i);
jd_i++;
jd_savepath = savefile.getParentFile().toString()+"\\"+jd_name;
System.out.println(jd_savepath + " in Control Thread");
File jk_file = new File(jd_savepath);
if(!jk_file.exists()) // 文件不存在时 创建一个文件
{
System.out.println("文件名没有重复,可以创建该文件。");
try
{
jk_file.createNewFile();
savePath = new String(jd_savepath);
break;
}
catch (IOException e)
{
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
}
}
System.out.println("Len of fiel in ControlThread " + fileLen);
long jd_block = fileLen/downThreadNum;
int c_1;
long j_2=0;
long j_3;
for(c_1=0;c_1<downThreadNum;c_1++)
{
if(c_1==downThreadNum)
j_3=fileLen-1;
else
j_3=j_2+jd_block;
DownThread downThread = new DownThread(j_2, j_3);
downThread.start();
j_2=j_3+1;
}
}
}
public static String getOKName(String filename,int num)
{
String reName;
if ((filename != null) && (filename.length() > 0))
{
int i = filename.lastIndexOf('.');
System.out.println(i +" the value of i ." );
if ((i > 0) && (i <= (filename.length() - 1)))
{ // 文件名正常
reName = filename.substring(0,i)+"("+num+")"+filename.substring(i);
return reName;
}
else if(i == 0) // 说明第一个字符就是 "."
{
reName = "("+num+")"+filename;
return reName;
}
else // 没有找到 字符 "."
{
reName = filename+"("+num+")";
return reName;
}
}
return ("("+num+")");
}
public long getTotalReadNum()
{
return this.totalReadNum;
}
public boolean getHasFinished()
{
return hasFinished;
}
public long getFileLength()
{
return fileLen;
}
private String downFielURL;
ControlThread ctrlThread;
private URL url;
private URLConnection conn; //
private String savePath; // 文件的保存路径
private int downThreadNum = 3; // 下载线程数量 至少一个线程 默认为 3个线程
private long fileLen; // 要下载的文件总长度
private boolean hasBegin = false; // 是否已经正确连接并且 开始下载
private boolean hasFinished = false; // 判断下载是否结束
private long totalReadNum = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -