我对Java非常陌生。我编写了一个Swing应用程序,它通过互联网下载特定的文件。
我想要做的是限制InputStream每秒读取n (比如10240字节,这可能会改变)字节。
一旦读取了整个文件,它应该将文件保存到本地目录(如C:\Downloads\ )中。
我猜我应该创建一个扩展到InputStream并覆盖它的方法的类,但是我不完全确定如何以及哪些方法来实现我的目标。
我使用这示例进行HTTP下载,这示例用于FTP。
HTTP示例;
package net.codejava.networking;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* A utility that downloads a file from a URL.
* @author www.codejava.net
*
*/
public class HttpDownloadUtility {
private static final int BUFFER_SIZE = 4096;
/**
* Downloads a file from a URL
* @param fileURL HTTP URL of the file to be downloaded
* @param saveDir path of the directory to save the file
* @throws IOException
*/
public static void downloadFile(String fileURL, String saveDir)
throws IOException {
URL url = new URL(fileURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String disposition = httpConn.getHeaderField("Content-Disposition");
String contentType = httpConn.getContentType();
int contentLength = httpConn.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 10,
disposition.length() - 1);
}
} else {
// extracts file name from URL
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
fileURL.length());
}
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
System.out.println("fileName = " + fileName);
// opens input stream from the HTTP connection
InputStream inputStream = httpConn.getInputStream();
String saveFilePath = saveDir + File.separator + fileName;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
System.out.println("File downloaded");
} else {
System.out.println("No file to download. Server replied HTTP code: " + responseCode);
}
httpConn.disconnect();
}
}FTP示例;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
/**
* A program demonstrates how to upload files from local computer to a remote
* FTP server using Apache Commons Net API.
* @author www.codejava.net
*/
public class FTPDownloadFileDemo {
public static void main(String[] args) {
String server = "www.myserver.com";
int port = 21;
String user = "user";
String pass = "pass";
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(server, port);
ftpClient.login(user, pass);
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// APPROACH #1: using retrieveFile(String, OutputStream)
String remoteFile1 = "/test/video.mp4";
File downloadFile1 = new File("D:/Downloads/video.mp4");
OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));
boolean success = ftpClient.retrieveFile(remoteFile1, outputStream1);
outputStream1.close();
if (success) {
System.out.println("File #1 has been downloaded successfully.");
}
// APPROACH #2: using InputStream retrieveFileStream(String)
String remoteFile2 = "/test/song.mp3";
File downloadFile2 = new File("D:/Downloads/song.mp3");
OutputStream outputStream2 = new BufferedOutputStream(new FileOutputStream(downloadFile2));
InputStream inputStream = ftpClient.retrieveFileStream(remoteFile2);
byte[] bytesArray = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
outputStream2.write(bytesArray, 0, bytesRead);
}
success = ftpClient.completePendingCommand();
if (success) {
System.out.println("File #2 has been downloaded successfully.");
}
outputStream2.close();
inputStream.close();
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}我想要的是限制这两个输入流的下载速度,以便在从远程获取这些文件的同时限制下载速度。
如果你能给我一个简单解释的例子,我会非常感激的。
发布于 2016-05-31 02:39:21
这有点原始,但它应该能满足您的要求(虽然没有测试)。
int bytesReadSinceSleep = 0;
long lastSleepTime = System.currentTimeMillis();
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
// increment bytes read this second
bytesReadSinceSleep += bytesRead;
// if we've passed the throttling point, sleep for the remainder of the second
if (bytesReadSinceSleep >= MAX_BYTES_PER_SECOND) {
// calculate time elapsed since last sleep
long timeElapsed = System.currentTimeMillis() - lastSleepTime;
// sleep for the remainder of 1 second (if there is a remainder)
Thread.sleep(Math.max(1000 - timeElapsed, 0));
// reset byte count
bytesReadSinceSleep = 0;
// reset sleep time
lastSleepTime = System.currentTimeMillis();
}
}如果BUFFER_SIZE不是MAX_BYTES_PER_SECOND的一个因素,并且您对节流率很特别,您可能需要使用接受偏移量和限制参数的read()重载来准确读取正确的值。
要获得更干净的解决方案,可以使用番石榴的RateLimiter
RateLimiter limiter = RateLimiter.create(MAX_BYTES_PER_SECOND);
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
limiter.acquire(bytesRead);
}发布于 2016-05-31 18:56:05
实际上,您可以扩展java.util.TimerTask而不是扩展InputStream。然后,使用java.util.Timer,您可以安排一个每秒执行一次的任务,直到整个文件下载为止。因此,您可以简单地定义要在一秒钟内下载的字节数。有时,下载可能低于您提供的限制(由于网络延迟),但这并不是一个冲突,因为在任何情况下,您的下载速度都会低于您提供的限制。此外,您可以随时更改下载速度,甚至在下载过程中也是如此。HTTP/HTTPS实现示例如下:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Timer;
import java.util.TimerTask;
public class DownloaderWithLimit extends TimerTask
{
private InputStream inputStream;
private OutputStream outputStream;
private int bytePerSecondLimit;
private Timer timer;
private float contentLength;
private float downloadedLength;
public DownloaderWithLimit (String urlToDownload, String destFileFullPath, int bytePerSecondLimit) throws IOException
{
this.bytePerSecondLimit = bytePerSecondLimit;
//
inputStream = createInputStreamFromUrl ( urlToDownload );
outputStream = new FileOutputStream ( new File ( destFileFullPath ) );
}
public void start(){
timer = new Timer();
timer.scheduleAtFixedRate(this, 1000, 1000);
}
public void run ()
{
try
{
byte[] buffer = new byte[bytePerSecondLimit];
int bytesRead = inputStream.read(buffer);
if(bytesRead != -1){
outputStream.write(buffer, 0, bytesRead);
} else {
outputStream.close();
inputStream.close();
timer.cancel();
}
downloadedLength += bytesRead;
System.out.println (bytesRead + " bytes per second. "+ NumberFormat.getPercentInstance ().format ( downloadedLength/contentLength )+" completed...");
}
catch ( IOException e )
{
e.printStackTrace();
throw new RuntimeException ( "Error During Download..." , e.getCause () );
}
}
private InputStream createInputStreamFromUrl ( String fileUrl ) throws IOException
{
URL url = new URL ( fileUrl );
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection ();
int responseCode = httpConn.getResponseCode ();
// always check HTTP response code first
if ( responseCode == HttpURLConnection.HTTP_OK )
{
String fileName = "";
String disposition = httpConn
.getHeaderField ( "Content-Disposition" );
String contentType = httpConn.getContentType ();
contentLength = httpConn.getContentLength ();
if ( disposition != null )
{
// extracts file name from header field
int index = disposition.indexOf ( "filename=" );
if ( index > 0 )
{
fileName = disposition.substring ( index + 10 , disposition.length () - 1 );
}
}
else
{
// extracts file name from URL
fileName = fileUrl.substring ( fileUrl.lastIndexOf ( "/" ) + 1 , fileUrl.length () );
}
System.out.println ( "Content-Type = " + contentType );
System.out.println ( "Content-Disposition = " + disposition );
System.out.println ( "Content-Length = " + contentLength );
System.out.println ( "fileName = " + fileName );
// opens input stream from the HTTP connection
InputStream inputStream = httpConn.getInputStream ();
return inputStream;
}
return null;
}
/**
* @return the bytePerSecondLimit
*/
public int getBytePerSecondLimit ()
{
return bytePerSecondLimit;
}
/**
* @param bytePerSecondLimit the bytePerSecondLimit to set
*/
public void setBytePerSecondLimit ( int bytePerSecondLimit )
{
this.bytePerSecondLimit = bytePerSecondLimit;
}
public static void main ( String[] args ) throws IOException
{
DownloaderWithLimit d = new DownloaderWithLimit ( "https://download.mozilla.org/?product=firefox-46.0.1-SSL&os=win64&lang=en-US" , "c:/firefox-46.0.1_x64.exe" , 10240);//10Kb/s
d.start ();
}
}具有利率限制的FTP示例如下:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
public class FtpDownloaderWithLimit extends TimerTask
{
private InputStream inputStream;
private OutputStream outputStream;
private int bytePerSecondLimit;
private Timer timer;
private float contentLength;
private float downloadedLength;
private FTPClient ftpClient;
public FtpDownloaderWithLimit (String ftpServer, int port, String username, String password, String srcFileRelativePath, String destFileFullPath, int bytePerSecondLimit) throws IOException
{
this.bytePerSecondLimit = bytePerSecondLimit;
//
inputStream = createInputStreamFromUrl ( ftpServer, port, username, password, srcFileRelativePath );
outputStream = new FileOutputStream ( new File ( destFileFullPath ) );
}
public void start(){
timer = new Timer();
timer.scheduleAtFixedRate(this, 1000, 1000);
}
public void run ()
{
try
{
byte[] buffer = new byte[bytePerSecondLimit];
int bytesRead = inputStream.read(buffer);
if(bytesRead != -1){
outputStream.write(buffer, 0, bytesRead);
} else {
boolean success = ftpClient.completePendingCommand();
if (success) {
System.out.println("File #2 has been downloaded successfully.");
}
outputStream.close();
inputStream.close();
timer.cancel();
}
downloadedLength += bytesRead;
System.out.println (bytesRead + " bytes per second. "+ NumberFormat.getPercentInstance ().format ( downloadedLength/contentLength )+" completed...");
}
catch ( IOException e )
{
e.printStackTrace();
throw new RuntimeException ( "Error During Download..." , e.getCause () );
}
}
private InputStream createInputStreamFromUrl(String ftpServer, int port,
String username, String password, String srcFileRelativePath) throws IOException{
ftpClient = new FTPClient();
ftpClient.connect(ftpServer, port);
ftpClient.login(username, password);
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
InputStream inputStream = ftpClient.retrieveFileStream(srcFileRelativePath);
return inputStream;
}
/**
* @return the bytePerSecondLimit
*/
public int getBytePerSecondLimit ()
{
return bytePerSecondLimit;
}
/**
* @param bytePerSecondLimit the bytePerSecondLimit to set
*/
public void setBytePerSecondLimit ( int bytePerSecondLimit )
{
this.bytePerSecondLimit = bytePerSecondLimit;
}
public static void main ( String[] args ) throws IOException
{
FtpDownloaderWithLimit d = new FtpDownloaderWithLimit ( "www.myserver.com" , 9111 /*sample port*/, "USERNAME", "PASSWORD", "/My/File/To/Downlaod.xxx", "c:/your-path-to-dest-file" , 10240);//10Kb/s
d.start ();
}
}希望这会有帮助。
https://stackoverflow.com/questions/37496058
复制相似问题