Có một tệp trực tuyến (chẳng hạn như http://www.example.com/information.asp
) tôi cần lấy và lưu vào một thư mục. Tôi biết có một số phương pháp để lấy và đọc từng tệp trực tuyến (URL), nhưng có cách nào để tải xuống và lưu tệp bằng Java không?
Có một tệp trực tuyến (chẳng hạn như http://www.example.com/information.asp
) tôi cần lấy và lưu vào một thư mục. Tôi biết có một số phương pháp để lấy và đọc từng tệp trực tuyến (URL), nhưng có cách nào để tải xuống và lưu tệp bằng Java không?
Câu trả lời:
Hãy dùng thử Java NIO :
URL website = new URL("http://www.website.com/information.asp");
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream("information.html");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
Việc sử dụng transferFrom()
có khả năng hiệu quả hơn nhiều so với một vòng lặp đơn giản đọc từ kênh nguồn và ghi vào kênh này. Nhiều hệ điều hành có thể chuyển byte trực tiếp từ kênh nguồn vào bộ đệm của hệ thống tập tin mà không thực sự sao chép chúng.
Kiểm tra thêm về nó ở đây .
Lưu ý : Tham số thứ ba trong transferFrom là số byte tối đa cần truyền. Integer.MAX_VALUE
sẽ chuyển tối đa 2 ^ 31 byte, Long.MAX_VALUE
sẽ cho phép tối đa 2 ^ 63 byte (lớn hơn bất kỳ tệp nào đang tồn tại).
8388608
TB?
transferFrom()
không được chỉ định để hoàn thành toàn bộ chuyển trong một cuộc gọi. Đó là lý do tại sao nó trả về một số lượng. Bạn phải lặp lại.
URL::openStream()
trả về chỉ là một luồng thông thường, có nghĩa là toàn bộ lưu lượng vẫn đang được sao chép thông qua các mảng Java [] thay vì còn lại trong bộ đệm riêng. Chỉ fos.getChannel()
thực sự là một kênh gốc, do đó, chi phí vẫn còn đầy đủ. Đó là lợi ích không từ việc sử dụng NIO trong trường hợp này. Ngoài việc bị phá vỡ, như EJP và Ben MacCann nhận thấy chính xác.
Sử dụng apache commons-io , chỉ một mã dòng:
FileUtils.copyURLToFile(URL, File)
copyURLToFile
với tham số hết thời gian chỉ khả dụng kể từ phiên bản 2.0 của thư viện Commons IO. Xem tài liệu Java
Cách sử dụng đơn giản hơn:
URL website = new URL("http://www.website.com/information.asp");
try (InputStream in = website.openStream()) {
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
}
InputStream.read()
trả về số 0 trừ khi bạn cung cấp bộ đệm có độ dài bằng 0 hoặc đếm, 'tạm dừng một chút' hoặc nếu không. Nó sẽ chặn cho đến khi ít nhất một byte được chuyển hoặc kết thúc luồng hoặc xảy ra lỗi. Yêu cầu của bạn về nội bộ Files.copy()
là vô căn cứ.
public void saveUrl(final String filename, final String urlString)
throws MalformedURLException, IOException {
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
in = new BufferedInputStream(new URL(urlString).openStream());
fout = new FileOutputStream(filename);
final byte data[] = new byte[1024];
int count;
while ((count = in.read(data, 0, 1024)) != -1) {
fout.write(data, 0, count);
}
} finally {
if (in != null) {
in.close();
}
if (fout != null) {
fout.close();
}
}
}
Bạn sẽ cần xử lý các trường hợp ngoại lệ, có thể là bên ngoài phương pháp này.
in.close
ném một ngoại lệ, fout.close
không được gọi.
BufferedInputStream
có chính xác không có hiệu lực trên thời gian chờ ổ cắm. Tôi đã bác bỏ rằng 'huyền thoại đô thị' trong các bình luận của tôi về 'chi tiết nền' mà bạn đã trích dẫn. Ba năm trước.
BufferedInputStream
"có thể gây ra những thất bại khó lường").
Đây là một câu hỏi cũ nhưng đây là một giải pháp ngắn gọn, dễ đọc, chỉ có JDK với các tài nguyên được đóng đúng cách:
public static void download(String url, String fileName) throws Exception {
try (InputStream in = URI.create(url).toURL().openStream()) {
Files.copy(in, Paths.get(fileName));
}
}
Hai dòng mã và không phụ thuộc.
import java.io.InputStream; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths;
Tải xuống một tệp yêu cầu bạn phải đọc nó, bằng cách nào đó bạn sẽ phải đi qua tệp theo một cách nào đó. Thay vì từng dòng, bạn chỉ có thể đọc nó theo byte từ luồng:
BufferedInputStream in = new BufferedInputStream(new URL("http://www.website.com/information.asp").openStream())
byte data[] = new byte[1024];
int count;
while((count = in.read(data,0,1024)) != -1)
{
out.write(data, 0, count);
}
Khi sử Java 7+
dụng, hãy sử dụng phương pháp sau để tải xuống một tệp từ Internet và lưu nó vào thư mục nào đó:
private static Path download(String sourceURL, String targetDirectory) throws IOException
{
URL url = new URL(sourceURL);
String fileName = sourceURL.substring(sourceURL.lastIndexOf('/') + 1, sourceURL.length());
Path targetPath = new File(targetDirectory + File.separator + fileName).toPath();
Files.copy(url.openStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
return targetPath;
}
Tài liệu ở đây .
Câu trả lời này gần như chính xác như câu trả lời được chọn nhưng với hai cải tiến: đó là một phương thức và nó đóng đối tượng FileOutputStream:
public static void downloadFileFromURL(String urlString, File destination) {
try {
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
transferFrom()
không được chỉ định để hoàn thành toàn bộ chuyển trong một cuộc gọi. Đó là lý do tại sao nó trả về một số lượng. Bạn phải lặp lại.
import java.io.*;
import java.net.*;
public class filedown {
public static void download(String address, String localFileName) {
OutputStream out = null;
URLConnection conn = null;
InputStream in = null;
try {
URL url = new URL(address);
out = new BufferedOutputStream(new FileOutputStream(localFileName));
conn = url.openConnection();
in = conn.getInputStream();
byte[] buffer = new byte[1024];
int numRead;
long numWritten = 0;
while ((numRead = in.read(buffer)) != -1) {
out.write(buffer, 0, numRead);
numWritten += numRead;
}
System.out.println(localFileName + "\t" + numWritten);
}
catch (Exception exception) {
exception.printStackTrace();
}
finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
catch (IOException ioe) {
}
}
}
public static void download(String address) {
int lastSlashIndex = address.lastIndexOf('/');
if (lastSlashIndex >= 0 &&
lastSlashIndex < address.length() - 1) {
download(address, (new URL(address)).getFile());
}
else {
System.err.println("Could not figure out local file name for "+address);
}
}
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
download(args[i]);
}
}
}
in.close
ném một ngoại lệ, out.close
không được gọi.
Cá nhân, tôi đã tìm thấy HTTPClient của Apache có khả năng nhiều hơn mọi thứ tôi cần làm liên quan đến vấn đề này. Đây là một hướng dẫn tuyệt vời về việc sử dụng HttpClient
Đây là một biến thể java7 khác dựa trên câu trả lời của Brian Risk với việc sử dụng câu lệnh try-with:
public static void downloadFileFromURL(String urlString, File destination) throws Throwable {
URL website = new URL(urlString);
try(
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
){
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
}
transferFrom()
không được chỉ định để hoàn thành toàn bộ chuyển trong một cuộc gọi. Đó là lý do tại sao nó trả về một số lượng. Bạn phải lặp lại.
Có thể tải xuống tệp bằng Apache HttpComponents
thay vì Commons-IO
. Mã này cho phép bạn tải xuống một tệp trong Java theo URL của nó và lưu nó tại đích cụ thể.
public static boolean saveFile(URL fileURL, String fileSavePath) {
boolean isSucceed = true;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(fileURL.toString());
httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
httpGet.addHeader("Referer", "https://www.google.com");
try {
CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity fileEntity = httpResponse.getEntity();
if (fileEntity != null) {
FileUtils.copyInputStreamToFile(fileEntity.getContent(), new File(fileSavePath));
}
} catch (IOException e) {
isSucceed = false;
}
httpGet.releaseConnection();
return isSucceed;
}
Ngược lại với dòng mã duy nhất:
FileUtils.copyURLToFile(fileURL, new File(fileSavePath),
URLS_FETCH_TIMEOUT, URLS_FETCH_TIMEOUT);
mã này sẽ cung cấp cho bạn kiểm soát nhiều hơn một quá trình và cho phép bạn chỉ định không chỉ có thời gian luân lưu nhưng User-Agent
và Referer
giá trị, trong đó rất quan trọng đối với nhiều các trang web.
Có rất nhiều câu trả lời thanh lịch và hiệu quả ở đây. Nhưng sự cụ thể có thể làm cho chúng ta mất một số thông tin hữu ích. Cụ thể, người ta thường không muốn coi lỗi kết nối là Ngoại lệ và người ta có thể muốn xử lý một số loại lỗi liên quan đến mạng khác nhau - ví dụ: để quyết định xem chúng ta có nên thử tải xuống không.
Đây là một phương pháp không đưa ra Ngoại lệ cho các lỗi mạng (chỉ dành cho các sự cố thực sự đặc biệt, như url không đúng định dạng hoặc sự cố ghi vào tệp)
/**
* Downloads from a (http/https) URL and saves to a file.
* Does not consider a connection error an Exception. Instead it returns:
*
* 0=ok
* 1=connection interrupted, timeout (but something was read)
* 2=not found (FileNotFoundException) (404)
* 3=server error (500...)
* 4=could not connect: connection timeout (no internet?) java.net.SocketTimeoutException
* 5=could not connect: (server down?) java.net.ConnectException
* 6=could not resolve host (bad host, or no internet - no dns)
*
* @param file File to write. Parent directory will be created if necessary
* @param url http/https url to connect
* @param secsConnectTimeout Seconds to wait for connection establishment
* @param secsReadTimeout Read timeout in seconds - trasmission will abort if it freezes more than this
* @return See above
* @throws IOException Only if URL is malformed or if could not create the file
*/
public static int saveUrl(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout) throws IOException {
Files.createDirectories(file.getParent()); // make sure parent dir exists , this can throw exception
URLConnection conn = url.openConnection(); // can throw exception if bad url
if( secsConnectTimeout > 0 ) conn.setConnectTimeout(secsConnectTimeout * 1000);
if( secsReadTimeout > 0 ) conn.setReadTimeout(secsReadTimeout * 1000);
int ret = 0;
boolean somethingRead = false;
try (InputStream is = conn.getInputStream()) {
try (BufferedInputStream in = new BufferedInputStream(is); OutputStream fout = Files
.newOutputStream(file)) {
final byte data[] = new byte[8192];
int count;
while((count = in.read(data)) > 0) {
somethingRead = true;
fout.write(data, 0, count);
}
}
} catch(java.io.IOException e) {
int httpcode = 999;
try {
httpcode = ((HttpURLConnection) conn).getResponseCode();
} catch(Exception ee) {}
if( somethingRead && e instanceof java.net.SocketTimeoutException ) ret = 1;
else if( e instanceof FileNotFoundException && httpcode >= 400 && httpcode < 500 ) ret = 2;
else if( httpcode >= 400 && httpcode < 600 ) ret = 3;
else if( e instanceof java.net.SocketTimeoutException ) ret = 4;
else if( e instanceof java.net.ConnectException ) ret = 5;
else if( e instanceof java.net.UnknownHostException ) ret = 6;
else throw e;
}
return ret;
}
Dưới đây là mã mẫu để tải phim từ internet bằng mã java:
URL url = new
URL("http://103.66.178.220/ftp/HDD2/Hindi%20Movies/2018/Hichki%202018.mkv");
BufferedInputStream bufferedInputStream = new BufferedInputStream(url.openStream());
FileOutputStream stream = new FileOutputStream("/home/sachin/Desktop/test.mkv");
int count=0;
byte[] b1 = new byte[100];
while((count = bufferedInputStream.read(b1)) != -1) {
System.out.println("b1:"+b1+">>"+count+ ">> KB downloaded:"+new File("/home/sachin/Desktop/test.mkv").length()/1024);
stream.write(b1, 0, count);
}
Có một vấn đề với việc sử dụng đơn giản là:
org.apache.commons.io.FileUtils.copyURLToFile(URL, File)
nếu bạn cần tải xuống và lưu các tệp rất lớn hoặc nói chung nếu bạn cần thử lại tự động trong trường hợp kết nối bị ngắt.
Những gì tôi đề xuất trong những trường hợp như vậy là Apache httpClient cùng với org.apache.commons.io.FileUtils. Ví dụ:
GetMethod method = new GetMethod(resource_url);
try {
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {
logger.error("Get method failed: " + method.getStatusLine());
}
org.apache.commons.io.FileUtils.copyInputStreamToFile(
method.getResponseBodyAsStream(), new File(resource_file));
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
method.releaseConnection();
}
Để tóm tắt (và bằng cách nào đó đánh bóng và cập nhật) các câu trả lời trước đó. Ba phương pháp sau đây là thực tế tương đương. (Tôi đã thêm thời gian chờ rõ ràng vì tôi nghĩ rằng chúng là bắt buộc, không ai muốn tải xuống bị đóng băng mãi mãi khi mất kết nối.)
public static void saveUrl1(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout))
throws MalformedURLException, IOException {
// Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
try (BufferedInputStream in = new BufferedInputStream(
streamFromUrl(url, secsConnectTimeout,secsReadTimeout) );
OutputStream fout = Files.newOutputStream(file)) {
final byte data[] = new byte[8192];
int count;
while((count = in.read(data)) > 0)
fout.write(data, 0, count);
}
}
public static void saveUrl2(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout))
throws MalformedURLException, IOException {
// Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
try (ReadableByteChannel rbc = Channels.newChannel(
streamFromUrl(url, secsConnectTimeout,secsReadTimeout)
);
FileChannel channel = FileChannel.open(file,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE)
) {
channel.transferFrom(rbc, 0, Long.MAX_VALUE);
}
}
public static void saveUrl3(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout))
throws MalformedURLException, IOException {
// Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
try (InputStream in = streamFromUrl(url, secsConnectTimeout,secsReadTimeout) ) {
Files.copy(in, file, StandardCopyOption.REPLACE_EXISTING);
}
}
public static InputStream streamFromUrl(URL url,int secsConnectTimeout,int secsReadTimeout) throws IOException {
URLConnection conn = url.openConnection();
if(secsConnectTimeout>0) conn.setConnectTimeout(secsConnectTimeout*1000);
if(secsReadTimeout>0) conn.setReadTimeout(secsReadTimeout*1000);
return conn.getInputStream();
}
Tôi không tìm thấy sự khác biệt đáng kể, tất cả dường như đúng với tôi. Chúng an toàn và hiệu quả. (Sự khác biệt về tốc độ dường như không liên quan - Tôi ghi 180Mb từ máy chủ cục bộ sang đĩa SSD trong thời gian dao động khoảng 1,2 đến 1,5 giây). Họ không yêu cầu các thư viện bên ngoài. Tất cả đều hoạt động với các kích thước tùy ý và (theo kinh nghiệm của tôi) chuyển hướng HTTP.
Ngoài ra, tất cả ném FileNotFoundException
nếu không tìm thấy tài nguyên (thường là lỗi 404) vàjava.net.UnknownHostException
nếu độ phân giải DNS không thành công; IOException khác tương ứng với các lỗi trong quá trình truyền.
(Được đánh dấu là wiki cộng đồng, vui lòng thêm thông tin hoặc chỉnh sửa)
Có phương thức U.fetch (url) trong thư viện gạch dưới-java .
pom.xml:
<groupId>com.github.javadev</groupId>
<artifactId>underscore</artifactId>
<version>1.45</version>
Mã ví dụ:
import com.github.underscore.lodash.U;
public class Download {
public static void main(String ... args) {
String text = U.fetch("https://stackoverflow.com/questions"
+ "/921262/how-to-download-and-save-a-file-from-internet-using-java").text();
}
}
Java
, nhưng câu trả lời của bạn trông giống nhưJavaScript
public class DownloadManager {
static String urls = "[WEBSITE NAME]";
public static void main(String[] args) throws IOException{
URL url = verify(urls);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream in = null;
String filename = url.getFile();
filename = filename.substring(filename.lastIndexOf('/') + 1);
FileOutputStream out = new FileOutputStream("C:\\Java2_programiranje/Network/DownloadTest1/Project/Output" + File.separator + filename);
in = connection.getInputStream();
int read = -1;
byte[] buffer = new byte[4096];
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
System.out.println("[SYSTEM/INFO]: Downloading file...");
}
in.close();
out.close();
System.out.println("[SYSTEM/INFO]: File Downloaded!");
}
private static URL verify(String url){
if(!url.toLowerCase().startsWith("http://")) {
return null;
}
URL verifyUrl = null;
try{
verifyUrl = new URL(url);
}catch(Exception e){
e.printStackTrace();
}
return verifyUrl;
}
}
Bạn có thể làm điều này trong 1 dòng bằng cách sử dụng bộ tải mạng cho Java :
new NetFile(new File("my/zips/1.zip"), "https://example.com/example.zip", -1).load(); //returns true if succeed, otherwise false.
Nếu bạn đứng sau proxy, bạn có thể đặt proxy trong chương trình java như sau:
Properties systemSettings = System.getProperties();
systemSettings.put("proxySet", "true");
systemSettings.put("https.proxyHost", "https proxy of your org");
systemSettings.put("https.proxyPort", "8080");
Nếu bạn không đứng sau proxy, đừng bao gồm các dòng trên trong mã của bạn. Mã làm việc đầy đủ để tải xuống một tệp khi bạn đứng sau proxy.
public static void main(String[] args) throws IOException {
String url="https://raw.githubusercontent.com/bpjoshi/fxservice/master/src/test/java/com/bpjoshi/fxservice/api/TradeControllerTest.java";
OutputStream outStream=null;
URLConnection connection=null;
InputStream is=null;
File targetFile=null;
URL server=null;
//Setting up proxies
Properties systemSettings = System.getProperties();
systemSettings.put("proxySet", "true");
systemSettings.put("https.proxyHost", "https proxy of my organisation");
systemSettings.put("https.proxyPort", "8080");
//The same way we could also set proxy for http
System.setProperty("java.net.useSystemProxies", "true");
//code to fetch file
try {
server=new URL(url);
connection = server.openConnection();
is = connection.getInputStream();
byte[] buffer = new byte[is.available()];
is.read(buffer);
targetFile = new File("src/main/resources/targetFile.java");
outStream = new FileOutputStream(targetFile);
outStream.write(buffer);
} catch (MalformedURLException e) {
System.out.println("THE URL IS NOT CORRECT ");
e.printStackTrace();
} catch (IOException e) {
System.out.println("Io exception");
e.printStackTrace();
}
finally{
if(outStream!=null) outStream.close();
}
}
Phương pháp 1 sử dụng kênh mới
ReadableByteChannel aq = Channels.newChannel(new url("https//asd/abc.txt").openStream());
FileOutputStream fileOS = new FileOutputStream("C:Users/local/abc.txt")
FileChannel writech = fileOS.getChannel();
Phương pháp thứ 2 bằng FileUtils
FileUtils.copyURLToFile(new url("https//asd/abc.txt",new local file on system("C":/Users/system/abc.txt"));
Phương pháp thứ 3 sử dụng
InputStream xy = new ("https//asd/abc.txt").openStream();
Đây là cách chúng tôi có thể tải xuống tệp bằng cách sử dụng mã java cơ bản và các thư viện bên thứ ba khác. Đây chỉ là để tham khảo nhanh. Vui lòng google với các từ khóa trên để có được thông tin chi tiết và các tùy chọn khác.