download a file in java using multi threading

11,040

transferTo is thread safe so you can only call it from one thread at a time.

If you want to read multiple parts of a file at once, the server has to support this and you need a stream for each portion of the file you are downloading.

For information on how to read portions of a file

Downloading a portion of a File using HTTP Requests

Reading the first part of a file using HTTP

Share:
11,040
Behzad Hassani
Author by

Behzad Hassani

Web Programmer and Developer Web Template Designer

Updated on June 04, 2022

Comments

  • Behzad Hassani
    Behzad Hassani almost 2 years

    I'm working on a downloader similar to IDM, I hava read This post about it. and I have implement my first-steps of code.

    Here is the Downloader Class's Code:

    package download.manager;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.nio.channels.ReadableByteChannel;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    
    public class Downloader implements Runnable{
    
        private String url;
        private int num;
        private long start;
        private long end;
        ReadableByteChannel rbc;
    
        public Downloader(String url, int num, long start, long end, ReadableByteChannel rbc) {
            this.url = url;
            this.num = num;
            this.start = start;
            this.end = end;
            this.rbc = rbc;
        }        
    
        @Override
        public void run() {
            download();
        }
    
        private void download(){
            try {
                System.out.println(num + " is executing");
                URL file = new URL(url);
                FileOutputStream stream = new FileOutputStream("tmp"+num);                        
                stream.getChannel().transferFrom(rbc, start, end);
            } catch (MalformedURLException ex) {
                Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex);
            }
    
        }
    
    }
    

    and this is my main function:

    package download.manager;
    
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.nio.channels.Channels;
    import java.nio.channels.ReadableByteChannel;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     *
     * @author Behzad
     */
    public class DownloadManager {
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
    
            URL file = null;
            ReadableByteChannel rbc = null;
            try {                       
                String url = "http://dl1.video.varzesh3.com/video/clip93/12/video/havashi/top5_save_derby_dortmond.mp4";
                file = new URL(url);
                rbc = Channels.newChannel(file.openStream());
                int size = file.openConnection().getContentLength(); 
                ExecutorService pool = Executors.newFixedThreadPool(4);
                int partSize = size / 4;
                pool.submit(new Downloader(url, 1, 0, partSize, rbc));
                pool.submit(new Downloader(url, 2, partSize, partSize, rbc));
                pool.submit(new Downloader(url, 3, 2 * partSize, partSize, rbc));
                pool.submit(new Downloader(url, 4, 3 * partSize, partSize, rbc));            
                pool.shutdown();
                pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
            } catch (MalformedURLException | InterruptedException ex) {
                Logger.getLogger(DownloadManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(DownloadManager.class.getName()).log(Level.SEVERE, null, ex);
            }
    
    
    
        }
    
    }
    

    but when I run this code the downloader downloads just first part of file. as you see in the picture

    enter image description here

    what should I do for this ?

    Here is updated download method :

    private void download(){
            try {
                System.out.println(num + " is executing");
                URL file = new URL(url);
                ReadableByteChannel rbc = Channels.newChannel(file.openStream());
                FileOutputStream stream = new FileOutputStream("tmp"+num);                        
                stream.getChannel().transferFrom(rbc, start, end);
            } catch (MalformedURLException ex) {
                Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex);
            }
    
        }
    
  • Behzad Hassani
    Behzad Hassani about 9 years
    Then You say I shoud define 4 ReadableByteChannel ? But I hava did it and nothing changed !
  • Vishy
    Vishy about 9 years
    @BehzadHassani can you update your code to reflect this?
  • Vishy
    Vishy about 9 years
    @BehzadHassani you have to tell the server to download different portions of the file, or you will just down the entire file 5 times.
  • Behzad Hassani
    Behzad Hassani about 9 years
    No Of course I want to download multiple portions of file @Peter Lawrey
  • Vishy
    Vishy about 9 years
    @BehzadHassani In that case you need to set urlConnection.setRequestProperty("Range", "Bytes=0-24"); to set the byte range you want to download. See the first link for more details. Note: the server might not accept this option.
  • Behzad Hassani
    Behzad Hassani about 9 years
    Thank you Peter, I will check it :) @Peter Lawrey