之前的项目中用到多线程下载文件,当然,说具体点我那是多个线程下载多个文件。实际上具体到某一文件时候还只是用了一个线程去下载,这种方式个人认为还是比较适合那中文件小而多的情况。 但这次不同了,项目中要下载并上传的文件进本都在30M以上。这样的话用以前的方式可就OUT了,于是就要使用一个文件多个线程下载的方式了。
同样的还是从代码入手:
import java . io . File ;
import java . io . UnsupportedEncodingException ;
import java . net . HttpURLConnection ;
import java . net . URL ;
public class Main {
public static int SINGAL = 0;
public static boolean START_DOWNLOAD = false;
private int threadNumber; 每个文件下载的线程数
private String fileName; 文件名
private String downLoadPath; 文件路径
private URL url ;
public Main( URL url ) {
super ( ) ;
this . url = url ;
this . threadNumber = 5;
this . downLoadPath = "c:/download/" ;
try {
this . fileName = java . net . URLDecoder . decode ( url . getFile ( ) . substring ( url . getFile ( ) . lastIndexOf ( "/" ) + 1, url . getFile ( ) . length ( ) ) , "GBK" ) ; //对Url进行转码操作
} catch ( UnsupportedEncodingException e) {
e. printStackTrace ( ) ;
}
}
public Main( int threadNumber, String fileName, String downLoadPath, URL url ) {
super ( ) ;
this . threadNumber = threadNumber;
this . fileName = fileName;
this . downLoadPath = downLoadPath;
this . url = url ;
}
public void download( ) throws Exception {
System . out. println ( "文件开始下载" ) ;
START_DOWNLOAD = true;
HttpURLConnection httpURLConnection = ( HttpURLConnection ) url . openConnection ( ) ;
int contentLength = httpURLConnection . getContentLength ( ) ;
int partLength = contentLength / threadNumber + 1; //得到该文件的大小
for ( int i= 0; i< threadNumber; i+ + ) { //根据自己的需要进行文件分块。
int length = partLength;
if ( i = = threadNumber - 1) {
length = contentLength - i * partLength;
}
DownloadThread dt = new DownloadThread( url , length , i * partLength, downLoadPath + fileName + ".part" + i) ;
dt. start ( ) ;
}
}
public int getThreadNumber( ) {
return threadNumber;
}
public void setThreadNumber( int threadNumber) {
this . threadNumber = threadNumber;
}
public String getDownLoadPath( ) {
return downLoadPath;
}
public void setDownLoadPath( String downLoadPath) {
this . downLoadPath = downLoadPath;
}
public String getFileName ( ) {
return fileName;
}
public void setFileName ( String fileName) {
this . fileName = fileName;
}
public URL getUrl ( ) {
return url ;
}
public void setUrl ( URL url ) {
this . url = url ;
}
public static void main( String [ ] args) throws Exception {
String urlAddress = "http://www.cssxblog.net/qin/mp3/aqzy.mp3" ;
URL url = new URL ( urlAddress) ;
int threadNumber = 5;
String fileName = "test.mp3" ;
String downLoadPath = "c:/download/" ;
new File ( downLoadPath) . mkdir ( ) ;
//下载
Main m = new Main( url ) ;
m. setThreadNumber( threadNumber) ;
m. download( ) ;
//合并文件
fileName = m. getFileName ( ) ;
Thread mergeFile = new MergeFile( threadNumber, downLoadPath, fileName) ;
mergeFile. start ( ) ;
}
}
import java . io . File ;
import java . io . FileInputStream ;
import java . io . FileOutputStream ;
import java . io . IOException ;
import java . io . InputStream ;
import java . io . OutputStream ;
public class MergeFile extends Thread {
private int threadNumber;
private String fileName;
private String downLoadPath;
public MergeFile( int threadNumber, String downLoadPath, String fileName) {
super ( ) ;
this . threadNumber = threadNumber;
this . downLoadPath = downLoadPath;
this . fileName = fileName;
}
public void run ( ) {
while ( ! ( Main. SINGAL = = 0 & & Main. START_DOWNLOAD) ) {
try {
Thread . sleep ( 5000) ;
} catch ( InterruptedException e) {
// TODO Auto-generated catch block
e. printStackTrace ( ) ;
}
}
try {
System . out. println ( "文件开始合并" ) ;
OutputStream bos = new FileOutputStream ( new File ( downLoadPath + fileName) , false) ;
for ( int i = 0; i< threadNumber; i+ + )
{
File file = new File ( downLoadPath + fileName + ".part" + i) ;
InputStream is = new FileInputStream ( file ) ;
byte [ ] buffer = new byte [ 1024] ;
int bytesRead;
while ( ( bytesRead = is. read ( buffer ) ) ! = - 1) {
bos. write ( buffer , 0, bytesRead) ;
}
is. close ( ) ;
file . delete ( ) ;
}
bos. close ( ) ;
System . out. println ( "文件合并完成" ) ;
} catch ( IOException e) {
// TODO Auto-generated catch block
e. printStackTrace ( ) ;
}
Main. START_DOWNLOAD = false;
}
public int getThreadNumber( ) {
return threadNumber;
}
public void setThreadNumber( int threadNumber) {
this . threadNumber = threadNumber;
}
public String getFileName ( ) {
return fileName;
}
public void setFileName ( String fileName) {
this . fileName = fileName;
}
public String getDownLoadPath( ) {
return downLoadPath;
}
public void setDownLoadPath( String downLoadPath) {
this . downLoadPath = downLoadPath;
}
}
import java . io . File ;
import java . io . FileOutputStream ;
import java . io . IOException ;
import java . io . InputStream ;
import java . io . OutputStream ;
import java . net . HttpURLConnection ;
import java . net . URL ;
public class DownloadThread extends Thread {
private URL url ;
private int length ;
private int offset;
private OutputStream bos;
private String filePath;
public void run ( ) {
Main. SINGAL+ + ;
System . out. println ( "线程" + this . getId ( ) + "开始下载" ) ;
try {
System . out. println ( "length:" + length ) ;
System . out. println ( "off:" + offset) ;
HttpURLConnection httpConnection = ( HttpURLConnection ) url . openConnection ( ) ;
httpConnection. setRequestProperty ( "RANGE" , "bytes=" + offset + "-" ) ;
注意:
此处一定要设置http请求的属性:这个用于设定请求读取数据的位置。如果不设定有可能数据会损坏。
InputStream ins = httpConnection. getInputStream ( ) ;
bos = new FileOutputStream ( new File ( filePath) , false) ;
byte [ ] buffer = new byte [ 1024] ; //设置缓存的大小
int bytesRead;
int size = 0;
while ( ( bytesRead = ins. read ( buffer ) ) ! = - 1) {
size + = bytesRead;
if ( size > length ) {
bytesRead = bytesRead - ( size - length ) ;
}
bos. write ( buffer , 0, bytesRead) ;
System . out. println ( "线程" + this . getId ( ) + "下载了" + bytesRead + "字节" ) ;
if ( size > length ) {
break ;
}
}
bos. close ( ) ;
} catch ( IOException e) {
// TODO Auto-generated catch block
e. printStackTrace ( ) ;
}
System . out. println ( "线程" + this . getId ( ) + "已经完成" ) ;
Main. SINGAL- - ;
}
public DownloadThread( URL url , int length , int offset, String filePath) {
super ( ) ;
this . url = url ;
this . length = length ;
this . offset = offset;
this . filePath = filePath;
}
public OutputStream getBos( ) {
return bos;
}
public void setBos( OutputStream bos) {
this . bos = bos;
}
}
以上代码不是自己写的,只是从别人那抄袭而来,此代码没有断点续传,后面准备尝试添加。