Prerequisite
Java RandomAccessFile ClassOverview
This article details the uses of HTTP Range header and its use in Download managers.HTTP Range Header
HTTP Range is a available in HTTP/1.1 and allow to specify the range of bytes. It allow you to specify the starting byte and ending byte of the requested stream.Range header allow many type of ranges we have used only byte range. Here is the syntax of byte range "Range: bytes=1-100", here 0 is starting byte and 100 is ending byte if ending byte is missing (Range: bytes=1-) it will be taken as the last byte in the file(EOF).
For more information on Range header click here
Range header used in Download manager
- Continuing the download: If you are downloading and download break in the middle because of some external or internal reason, without range header you have to start from the beginning range header allow you to specify the starting byte of the download.
- Multi-threading download: you can divide the download of large file into multiple chunks and download them in parallel.
Below is the code which divide the file in chunks and download in parallel, this program after configuring properly gives you 50% better performance then Orbit download manager.
package www.directi.com.junk; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.Date; /* * this class downloads a file from from given URL in multiple parts. It uses http range header * $author = Paras Malik(masterofmasters22@gmail.com) * $date = june 25, 2011 * */ public class DownloadInChunks implements Runnable { private static String fileURL = "sourceFileLink"; //file to be downloaded private static final String targetFileName = "targetFileName"; private static final int MAX_BUFFER_SIZE = 1024 * 64 * 4; //maximum number of bytes for which connection will be probed private static int chunkOfFile = 1024 * 1024; //size of one chunk of file to be downloaded private int downloadStartingByte; private int downloadEndingByte; static int fs; public DownloadInChunks(int downloadStartingByte, int downloadEndingByte) { this.downloadStartingByte = downloadStartingByte; this.downloadEndingByte = downloadEndingByte; } public static void main(String s[]) throws IOException { System.out.println(new Date()); int downloadStartingByte = 0; int downloadEndingByte = chunkOfFile; int fileSize = getFileSize(); fs = fileSize; while (fileSize > downloadStartingByte) { if (downloadEndingByte == fileSize) new Thread(new DownloadInChunks(downloadStartingByte, -1)).start(); else new Thread(new DownloadInChunks(downloadStartingByte, downloadEndingByte)).start(); downloadStartingByte = downloadEndingByte; if (downloadEndingByte + chunkOfFile <= fileSize) downloadEndingByte = downloadEndingByte + chunkOfFile; else downloadEndingByte = fileSize; } } static int getFileSize() throws IOException { URL url = new URL(fileURL); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.connect(); if (connection.getResponseCode() != 200) { System.out.println("Error return code != 200"); } int contentLength = connection.getContentLength(); connection.disconnect(); return contentLength; } public void downloadPartOfFile(int startingByte, String endingByte) throws IOException { URL url = new URL(fileURL); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); int downloaded = 0; connection.setRequestProperty("Range", "bytes=" + startingByte + "-" + endingByte); //is endingByte is empty string http request all the bytes till EOF from given starting byte. connection.connect(); if (connection.getResponseCode() != 206) { // http return 206 as signal of OK if request is send with range header System.out.println("Error return code != 206"); } int contentLength = connection.getContentLength(); RandomAccessFile file = new RandomAccessFile(targetFileName, "rw"); file.seek(startingByte); InputStream stream = connection.getInputStream(); while (true) { byte buffer[]; if (contentLength - downloaded > MAX_BUFFER_SIZE) { buffer = new byte[MAX_BUFFER_SIZE]; } else { buffer = new byte[contentLength - downloaded]; } int read = stream.read(buffer); if (read == -1 || downloaded == contentLength) break; file.write(buffer, 0, read); downloaded += read; } file.close(); } @Override public void run() { try { if (downloadEndingByte == -1) downloadPartOfFile(downloadStartingByte, ""); else downloadPartOfFile(downloadStartingByte, String.valueOf(downloadEndingByte)); } catch (IOException e) { e.printStackTrace(); } } }
No comments:
Post a Comment