使用多线程下载 java 中的文件
download a file in java using multi threading
我正在开发一个类似于 IDM 的下载器,我已经阅读了 This post 相关内容。我已经实现了我的第一步代码。
这是下载器 Class 的代码:
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);
}
}
}
这是我的主要功能:
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);
}
}
}
但是当我 运行 这段代码时,下载器只下载文件的第一部分。如图所示
我该怎么办?
这里是更新的下载方法:
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);
}
}
transferTo
是线程安全的,因此您一次只能从一个线程调用它。
如果您想一次读取一个文件的多个部分,服务器必须支持这一点,并且您需要为正在下载的文件的每个部分创建一个流。
有关如何读取部分文件的信息
我正在开发一个类似于 IDM 的下载器,我已经阅读了 This post 相关内容。我已经实现了我的第一步代码。
这是下载器 Class 的代码:
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);
}
}
}
这是我的主要功能:
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);
}
}
}
但是当我 运行 这段代码时,下载器只下载文件的第一部分。如图所示
我该怎么办?
这里是更新的下载方法:
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);
}
}
transferTo
是线程安全的,因此您一次只能从一个线程调用它。
如果您想一次读取一个文件的多个部分,服务器必须支持这一点,并且您需要为正在下载的文件的每个部分创建一个流。
有关如何读取部分文件的信息