java - 使用 RandomAccessFile 在 Java 中通过多线程下载不正确的文件

标签 java multithreading inputstream httpurlconnection java-io

尊敬的前辈您好:)

我的目标:通过使用 Java 中的多线程,在给定 URL 的情况下下载 URL 资源,即将单个文件下载为多个部分(很像 IDM 的做法)并在结束时下载下载,将它们全部合并为 1 个最终文件。例如,如果图像大小为 260KB,我想将其下载到 2 个线程中,其中 1st Thread 应从 0KB 下载到 130KB & 2nd Thread 应从 131KB 到 260KB 下载。

技术使用: Java、RandomAccessFile、多线程、InputStreams

问题:此代码适用于 1 个线程,即,如果我运行从 0 到 260KB 的单个线程。但是当我尝试分块下载它时,出现以下错误:

  1. 它将下载额外的垃圾KB,即对于260KB的文件,将下载300+KB。

  2. 有时会下载确切的 260KB,但文件已损坏,我无法打开图像。

请帮助我。整整一周以来我已经尝试了很多,但我似乎无法理解这个问题。

初始代码

void InitiaeDownload
{


        HttpURLConnection uc = (HttpURLConnection) url.openConnection();
        uc.connect();
        long fileSize = uc.getContentLengthLong();
        System.out.println("File Size = "+ fileSize );
        uc.disconnect();

//------------------

        long chunkSize = (long) Math.ceil(fileSize/2);

        long startFrom = 0;
        long endRange = (startFrom + chunkSize) - 1;

        System.out.println("Chunk Size = " + chunkSize);
        System.out.println("Part 1 :: Start = " + startFrom + "\tEnd To = " + endRange);

        Thread t1 = new MyThread(url, file, startFrom, endRange);
        t1.start();

        startFrom += chunkSize;
        long temp = endRange + chunkSize;
        endRange = temp + (fileSize-temp);  //also add remaining bytes

        System.out.println("Part 2 :: Start = " + startFrom + "\tEnd To = " + endRange );

        Thread t2 = new MyThread(url, file, startFrom, endRange);
        t2.start();
}

现在,

线程类别

class MyThread extends Thread {

    private URL url;
    private long startFrom;
    private long range;
    private InputStream inStream;
    private RandomAccessFile file;


    public MyThread(URL url, RandomAccessFile file, long startFrom,  long range)    //parameterized constructor
    {

        this.url = url;
        this.file = file;
        this.startFrom = startFrom;
        this.range = range;

    }

    public void run() {

        System.out.println("Thread Running..");

        Thread.currentThread().setPriority(MAX_PRIORITY);

        System.setProperty("http.proxyHost", "192.168.10.50");
        System.setProperty("http.proxyPort", "8080");   

        HttpURLConnection uc = null;
        try  {

            uc = (HttpURLConnection) url.openConnection();

            uc.setRequestProperty("Range", "bytes="+startFrom+"-"+range);
            uc.connect();

            inStream = uc.getInputStream();
            System.out.println("Starting Download");

            int bytesRead = 0;
            byte[] buffer = new byte[ (int) (range-startFrom) ];


            file.seek(startFrom);   //adjusted start of file

            while( (bytesRead = inStream.read(buffer) ) != -1 ) {

                file.write(buffer, 0, bytesRead);
            }

            System.err.println("Download Completed!");
            uc.disconnect();
        }
        catch(IOException e) {
            System.err.println("Exception in " + Thread.currentThread().getName() + "\t Exception = " + e );
        }           
    }  ///END OF run()  
} ////END OF MyThread Class

最佳答案

您正尝试从多个线程写入同一个file对象。当您查找()或写入()时,它只有一个执行此操作的 View 。

如果您想同时在不同的位置写入相同的内容,每个线程都必须拥有自己的 RandomAccessFile 对象,即使它们都指向同一个底层文件。

顺便说一句:更改 IO 绑定(bind)进程的线程优先级可能起的作用很小(除非您是管理员,否则什么也做不了)

关于java - 使用 RandomAccessFile 在 Java 中通过多线程下载不正确的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22742617/

相关文章:

java - C++ 引用和 Java 引用

c - 向 C 中的 pthreads 发送和捕获信号

java.net.Socket > InputStream > BufferedReader.read(char[]) 阻塞线程

c++ - 从 10 以外的其他基数的输入流中读取

java - 套接字关闭与输入流关闭

Java 更改卷 OSX

java - 如何使用 Java 8 流使用接收两个参数的函数将映射的键+值转换为新值?

java - 无法接收服务器完整响应

java - 无法运行程序 "C:\Program Files\Java\jdk1.8.0_221\jre\bin\java"目录名无效

c# - WPF 线程错误(处理了无效操作异常)