自己编写了一个多线程的代码,从localhost上面下载一个exe文件,下载完成之后,对比文件的总长度是没有问题的,但是exe文件无法执行,请大神帮忙看看public class MulThreadDownLoadTest {

private File file ;

public static void main(String args []) throws Exception{

String path = "http://localhost:8080/test/chrome.exe";

 new MulThreadDownLoadTest().download(path,3);

}
public void download(String path, int threadCount ) throws Exception{
URL url = new URL(path);
HttpURLConnection  con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(500);
if(con.getResponseCode() == 200){
String fileName = getFileName(path); //获取文件名

file = new File(fileName); 
 int ContentLength = con.getContentLength();//获取响应的长度

 System.out.println("下载文件大小"+ContentLength);
RandomAccessFile accessFile = new RandomAccessFile(file,"rwd");
accessFile.setLength(ContentLength);

//计算每个线程的下载长度为多少
 int tasksize = (ContentLength%threadCount == 0 ? ContentLength/threadCount :  ContentLength/threadCount+ 1);

 accessFile.close();
 for(int threadid = 0; threadid < threadCount ;threadid++ ){
new MulThreadDownLoad(path,file,tasksize,threadid).start();
}
}
}


public static   String getFileName(String path){

return  path.substring(path.lastIndexOf("/")+1);
}
}
public class MulThreadDownLoad extends Thread {

private String path;
private File file;
private  int tasksize;
private int threadid;

public MulThreadDownLoad(String path ,File file , int tasksize, int threadid){
this.path = path;   //文件路径
this.file = file; //文件
this.tasksize = tasksize; //线程的下载量
this.threadid = threadid; //线程的id
}
@Override
public void run() {
try {


int startPoint = threadid * tasksize;     //每条线程写入文件的起点
int endPoint = (threadid + 1 ) * tasksize -1 ; //每条线程写入文件的终点

RandomAccessFile accessFile = new RandomAccessFile(file,"rwd");
accessFile.seek(startPoint);

HttpURLConnection con = (HttpURLConnection)  new URL(path).openConnection();
con.setConnectTimeout(500);
con.setRequestMethod("GET");
con.setRequestProperty("Range", "bytes = "+startPoint+"-"+endPoint);

if(con.getResponseCode() == 206){


InputStream ins = con.getInputStream();
byte [] buffer = new byte [1024];
int length = 0;
while((length = ins.read(buffer)) != -1 ){  //将读取的字节写入文件中
accessFile.write(buffer, 0, length);
}

accessFile.close();
ins.close();
}

System.out.print((threadid +1 )+"线程已经下载完成 :");
System.out.println("bytes = "+startPoint+"-"+endPoint);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}}
谢谢各位大神帮忙  多线程java 

解决方案 »

  1.   

    你确定你服务端支持http range么?可以在if(con.getResponseCode() == 206)加个else做测试
    另外你的accessFile.setLength(ContentLength);可以去掉试试,因为你seek时是可以超出length的,这样可以看看你的下载后的文件是不是真的和源文件一样大最后你计算每个chunk大小的算法应该改一改,对于最后一个chunk之外的可以这样算,但是最后一个一定要到最后
      

  2.   

    额  的确是不支持http range 我用的是tomcat ,这个能在tomcat里面设置么?
      

  3.   

    特意去看了下,对于静态资源tomcat是支持range的,这符合逻辑,作为一个http服务器应该支持这个协议的特性,你是怎样测试的tomcat不支持range?你的test后面是个静态文件夹吧?不是一个自己写的servlet?
      

  4.   

    我按照你说的在if(con.getResponseCode() == 206)加个了else测试了一下,执行的是else块里面的代码,test是我新建的一个java web项目,我直接把可执行文件放在了webroot文件夹下面了
      

  5.   

    应该是每个下载长度的问题吧,最后一个线程所要下载的长度应该是小于或者等于你代码里的tasksize值
    // 计算每个线程需要下载多少byte的文件
    long perSize = size % threadCount == 0 ? size / threadCount : (size / threadCount + 1);// 初始化若干个下载线程
    for(int i = 0; i < threadCount; i++){
         if(i != (threadCount - 1)){
             threads[i] = new JFileDownloadThread(urlPath, destFile, 
                            i * perSize, perSize, notificationThread);
                }else{
                    threads[i] = new JFileDownloadThread(urlPath, destFile, 
                            i * perSize, size - (threadCount - 1) * perSize, notificationThread);
                }
               threads[i].setPriority(8);
    //            threads[i].start();
            }给你看一个我写的完整示例:
    http://www.cnblogs.com/tiantianbyconan/archive/2013/02/20/2919132.html
      

  6.   

    可以用RandomAccessFile来解决这个问题,可以把InputStream里的指定的部分写到本地保存文件的相应位置,不会出现序列不一致的情况raf = new RandomAccessFile(destFile, "rw");
    raf.setLength(conn.getContentLength()); // 设置本地保存文件的大小
    raf.setLength(conn.getInputStream().available());
    // 设置获得的InputStream对象的读入位置
    is.skip(startPos);
    // 设置本地保存的文件开始写入位置
    raf.seek(startPos);
      

  7.   

    tomcat如果是静态的话(DefaultServlet)是支持Range头的。话说,按照协议,貌似你的格式是错误的,范围数据单位后面的等号前后是不要允许有空白符号的       byte-ranges-specifier = bytes-unit "=" byte-range-set
    这个里面的空格并不是协议中的空格,协议中的空格,用SP表示
    比如Content-Range中的
           byte-content-range-spec = bytes-unit SP
                                     byte-range-resp-spec "/"
                                     ( instance-length | "*" )
    比如Warning中的
           warning-value = warn-code SP warn-agent SP warn-text
                                                 [SP warn-date]con.setRequestProperty("Range", "bytes="+startPoint+"-"+endPoint);
      

  8.   

    HTTP/1.1 (RFC2616)中的语法,请参考
    http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2