0 0

「多线程下载」线程无法完整读取数据20

这是线程代码,每个线程负责下载文件的一段:

package download;

import java.io.*;
import java.net.*;

public class DownloadThread extends Thread{
    private InputStream in; //网络下载文件输入流
    private RandomAccessFile out; //下载文件输出流
    private URL downURL;
    private TaskInfo taskInfo;
    private long startP;
    private long block;
    private int threadID;
    private boolean finished=false;
    private boolean error=false;
                    
    public DownloadThread(TaskInfo taskInfo,int threadID){
        this.taskInfo=taskInfo; 
        this.threadID=threadID;
    }
      
    public boolean isFinished(){
        return finished;
    }

    public boolean isError(){
        return error;
    }
   
    public void run(){
        HttpURLConnection http;
        int errCount = 0; //报文申请错误计数
        quit:
        for(int i=0;; i++){
            try{
                if(i>0){
                    System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"正在重新连接服务器......");
                    Thread.sleep(2000); //两秒后重新发起连接
                }
            }
            catch(Exception e){
            }
           
            try{
                downURL=new URL(taskInfo.getDownURL());
                http=(HttpURLConnection)downURL.openConnection();
                //setHeader(http);
                http.setConnectTimeout(5000); //防止因为网络异常而僵死
                http.setReadTimeout(5000);
               
                startP = taskInfo.getDownPos()[threadID][0]; //更新线程进度信息(适用于重新连接服务器的情况)
                block = taskInfo.getDownPos()[threadID][1];
                String sProperty = "bytes=" + startP + "-";
                http.setRequestProperty("Range",sProperty);
                System.out.println("http response code: "+http.getResponseCode());
                if(http.getResponseCode() != HttpURLConnection.HTTP_OK && http.getResponseCode() != HttpURLConnection.HTTP_PARTIAL){
                    error = true;
                    break;
                }
                in=http.getInputStream();
                out=new RandomAccessFile(taskInfo.getSaveFilePath(),"rw");
            }
            catch(IOException e1){
                System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"报文申请错误!");
                if((errCount++)>=19) break; //连续20次报文申请错误,判定线程错误,跳出for循环
                continue; //线程报文申请错误,重新发起连接
            }

            errCount = 0;//重置计数
            byte[] buffer=new byte[1024];
            int len=0;
            long localSize=0;
            long step = 0;
            System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"开始下载");
           
            try {
                out.seek(startP);
                step=(block>1024)?1024:block; //精确控制in.read所读取的最大长度,否则当block<1024时,len不准确,导致localSize出错。
                while (((len = in.read(buffer,0,(int)step))>0)&&localSize<=block) { //一定要>0,不能>-1或!-1,因为不负责文件末段的线程完成后返回0
                    if(taskInfo.isStopped()) break;
                    if(taskInfo.isError()) break quit; //任一线程error,直接终止其他所有线程
                    out.write(buffer,0,len);
                    localSize+=len;
                    //修改文件下载线程进度信息
                    taskInfo.getDownPos()[threadID][0]=startP+localSize;
                    taskInfo.getDownPos()[threadID][1]=block-localSize;
                    long tmp_block=block-localSize;
                    step=(tmp_block>1024)?1024:tmp_block;
                    //更改下载文件长度
                    taskInfo.setDownLength(len);
                }
                System.out.println("线程"+threadID+" read len:"+len);
                System.out.println("线程"+threadID+" block-localSize="+(block-localSize));
                out.close();
                in.close();
                http.disconnect();
               
                if(taskInfo.isStopped()){
                    System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"暂停下载");
                    break;
                }
                else if((block-localSize)!=0){ //len=-1跳出while循环,猜测原因是url所对应的资源有变化。
                    System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"获取数据错误");
                    error = true;
                    break;
                }
                else{
                    finished=true;
                    System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"完成下载");
                    break; //下载完成,跳出循环,防止线程重新启动。
                }
            }
            catch(Exception e2){ //in.read(buffer)发生异常,java.net.SocketTimeoutException: Read timed out
                System.out.println("文件 ["+taskInfo.getFileName()+"] 线程"+threadID+"获取数据超时");
                try{
                    out.close();
                    in.close();
                    http.disconnect();  
                }
                catch(Exception e1){
                }
                continue; //线程下载出错,重新发起连接
            }
        }
        if(errCount>19) error = true; //报文申请20次仍不成功,判定该线程错误
    }      
}


测试:下载pconline的软件

发现几个问题:
1、出现http response code是416(范围请求错误),但我调试发现请求的数据范围并没有错。
2、有时候,负责下载中间断数据的线程,在下载过程中in.read()返回-1,并且这时候数据并没有下载完整。「正常情况下应该不断读取数据,直到read()返回0对吧」

被这两个问题困扰很久,请大家不吝赐教,多谢!
2013年3月28日 21:37
目前还没有答案

相关推荐

    多线程读取文件

    在IT领域,多线程是并发处理任务的关键技术,尤其在读取大文件时,能够显著提高程序的执行效率。本文将围绕“多线程读取文件”这一主题,结合给定的标签“源码”和“工具”,深入探讨如何在Java等编程语言中实现这一...

    delphi 多线程 读取数据

    在IT领域,多线程是一种常见的编程技术,用于提高程序的执行效率,特别是在处理大量数据时。本示例中,我们关注的是如何在Delphi环境中使用TThread组件进行多线程编程,以便并行读取文本文件数据。下面将详细阐述这...

    java多线程读取文件

    Java多线程读大文件 java多线程写文件:多线程往队列中写入数据

    易语言多线程读取大文本文件

    在处理大数据量的文本文件时,单线程读取可能会导致程序响应慢或者占用过多系统资源,因此,采用多线程技术进行读取就显得尤为重要。 在“易语言多线程读取大文本文件”这个主题中,核心概念是多线程和文件I/O操作...

    易语言多线程读取大文本文件源码

    本源码示例是关于如何在易语言中实现多线程读取大文本文件,这对于处理大量数据或长时间运行的任务尤其有用。以下将详细介绍这一技术及其应用。 首先,理解多线程的概念至关重要。在单线程环境中,程序按照顺序执行...

    多线程读取大文件

    在文件传输中,可以多线程下载大文件,提高下载速率。 总结来说,多线程读取大文件是提升系统性能的有效手段,它结合了并行处理和I/O操作优化,减少了整体处理时间。开发者应根据具体的应用场景和语言特性,选择...

    基于多线程和gdal类库的影像读写

    然而,多线程编程也需要注意线程同步问题,防止数据竞争和死锁,确保数据的一致性和完整性。 在用户交互体验方面,本程序还引入了进度条功能。进度条能直观地展示任务的完成状态,给予用户反馈,提高用户体验。在...

    用多线程实现串口读写数据以及文件的读写

    本教程聚焦于如何利用多线程实现串口(Serial Port)读写数据及文件的读写操作,这对于理解和开发高效通信系统至关重要。 首先,我们要理解什么是串口通信。串口通信是一种基于串行数据传输的通信方式,它通过一条...

    C# httpwebrequest 多线程下载类

    在C#编程中,开发人员经常需要处理网络数据的下载任务,特别是在大数据量或需要优化性能的情况下,多线程技术的应用变得尤为重要。本篇将详细探讨如何基于`HttpWebRequest`和多线程来实现一个高效的文件下载类。 ...

    DELPHI开发的多线程HTTP下载

    8. **IdHttpDownload.pas**:这个文件很可能包含了自定义的下载类,扩展了 TIdHTTP 功能,用于处理多线程下载的具体操作。 9. **httpdown.res**:这是一个资源文件,可能包含了应用程序的图标和其他资源。 在实现...

    QT多线程技术读取文档内容到程序里

    Qt Creator 多线程读取文件到程序显示 利用QT Creator多任务读取一个文档到程序里 为了防止直接读取文件里的内容太大而发生卡顿,于是多线程读取将更高效的解决这个问题。 效果图如下: 其中pro文件无需改动,...

    多线程导入excel 数据

    在Java编程中,多线程导入Excel数据是一项常见的任务,特别是在大数据处理和高并发场景下。这个场景通常涉及到性能优化和资源管理,以确保系统稳定性和数据一致性。下面将详细阐述多线程导入Excel数据的核心知识点。...

    多线程下载器.zip易语言项目例子源码下载

    在这个项目中,易语言被用来构建多线程下载器的核心逻辑,包括任务管理、线程控制、数据接收与合并等关键部分。 1. **任务管理**:在项目中,每个下载任务会被表示为一个独立的对象,包含文件URL、保存路径、已下载...

    SpringBoot版本的多线程下载文件,分段下载文件

    首先,多线程下载文件是一种提高下载速度的方法,通过将大文件分成多个小部分,每个部分由一个单独的线程负责下载,从而充分利用多核处理器的并行处理能力。在Java中,我们可以使用`java.util.concurrent`包中的`...

    海康网络相机利用SDK 多线程读取图像程序

    总结来说,"海康网络相机利用SDK多线程读取图像程序"是一个综合性的项目,涵盖了网络通信、图像处理、多线程编程等多个领域的技术,对开发者的技能要求较高。通过这样的实践,开发者不仅能深入理解海康威视SDK的使用...

    C#处理大容量数据,及多线程简单应用

    以下将详细介绍“C#处理大容量数据,及多线程简单应用”这一主题。 首先,当我们面临大量数据时,一个关键的考虑点是避免阻塞主线程,尤其是对于UI(用户界面)应用。在C#中,长时间运行的任务会阻塞UI线程,导致...

    Qt数据库利用线程读取MySql数据

    而QThread是Qt提供的线程类,用于实现多线程编程,有助于提高程序的响应性和性能。 首先,我们需要了解如何在Qt中连接到MySQL数据库。Qt的SQL模块提供了QMYSQL driver,使得我们可以连接到MySQL服务器。在VS2010中...

    qt 线程池实现多线程下载

    在编程领域,多线程是提高程序执行效率和响应能力的一种常见技术,特别是在处理I/O密集型任务如网络下载时。Qt是一个强大的跨平台应用程序开发框架,提供了丰富的API来支持多线程编程。本篇文章将深入讲解如何使用Qt...

    多线程读取摄像头并对图像进行处理(C++)

    多线程读取摄像头并对图像进行处理(C++)

    Java多线程下载器

    Java多线程下载器是一种利用Java编程语言实现的高效文件下载工具,它通过将大文件分割成多个部分并同时下载,显著提高了下载速度。在Java中实现多线程下载器涉及许多关键概念和技术,包括线程、并发控制、网络I/O...

Global site tag (gtag.js) - Google Analytics