当前位置:  开发笔记 > 编程语言 > 正文

如何使用Java从Internet下载和保存文件?

如何解决《如何使用Java从Internet下载和保存文件?》经验,为你挑选了11个好方法。

有一个在线文件(例如http://www.example.com/information.asp)我需要抓取并保存到目录中.我知道有几种方法可以逐行获取和读取在线文件(URL),但有没有办法只使用Java下载和保存文件?



1> dfa..:

提供的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);

使用transferFrom()可能不是一个简单的循环从源信道的读取和写入这个频道有效得多.许多操作系统可以直接从源通道将字节传输到文件系统缓存中,而无需实际复制它们.

在这里查看更多相关信息.

注意:transferFrom中的第三个参数是要传输的最大字节数. Integer.MAX_VALUE将最多传输2 ^ 31个字节,Long.MAX_VALUE最多允许2 ^ 63个字节(大于现有的任何文件).


这只会下载文件的前16MB:http://stackoverflow.com/questions/8405062/downloading-files-with-java
@kirdie,如果我想要超过'8388608` TB?
单个电话是不够的.`transferFrom()`isnt'指定在一次调用中完成整个传输.这就是它返回计数的原因.你必须循环.
使用Java 7 try-with-resource关闭所有三个:try(InputStream inputStream = website.openStream(); ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream); FileOutputStream fileOutputStream = new FileOutputStream(outputFileName)){fileOutputStream.getChannel().transferFrom (readableByteChannel,0,1 << 24); }
为什么这个答案被接受?`URL :: openStream()`只返回一个常规流,这意味着整个流量仍然通过Java byte []数组复制,而不是保留在本机缓冲区中.只有`fos.getChannel()`实际上是一个原生通道,所以开销仍然是完整的.在这种情况下,使用NIO的收益为零.除了被打破之外,正如EJP和Ben MacCann正确地注意到的那样.
@willcodejavaforfood:它只是16777216的别名.任意长块大小.一个神奇的幻想(小心吧!)
1 << 24只是看起来如此随意,会不会像Long.MAX_VALUE那样更有意义?
嘿那个狡猾的位是什么?
有没有办法用这种方法跟踪下载的进度?
如果该文件大于16777216字节怎么办?
如果您的文件大于16 MB,则使用Integer.MAX_VALUE(如果文件大于2 GB,则使用Long.MAX_VALUE).
@will,换班只是表示2 ^ 24的另一种方式(他从频道中读取的数量)
抱歉听起来像一个总菜鸟,但我应该关闭fos吗?不管怎样,谢谢,它完美无缺!
如果您正在使用NIO,请保持一致并使用`FileChannel.open(Paths.get("information.html"),StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING,StandardOpenOption.WRITE)`而不是`FileOutputStream`

2> 卢声远 Shengyua..:

使用apache commons-io,只需一行代码:

FileUtils.copyURLToFile(URL, File)


太好了!正是我在寻找的!我知道Apache库已经涵盖了这一点.顺便说一下,建议使用带有超时参数的重载版本!
...并且在使用该重载版本时,请记住超时以毫秒而非秒为单位指定.
请注意,带有超时参数的`copyURLToFile`仅在Commons IO库的2.0版本之后可用.参见[Java docs](http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FileUtils.html)
如果必须将基本身份验证标头添加到请求中该怎么办?有解决方法吗?
虽然这是"短暂的",但它实际上非常慢.
本机Java解决方案比外部库IMO更好.

3> xuesheng..:

更简单的nio用法:

URL website = new URL("http://www.website.com/information.asp");
try (InputStream in = website.openStream()) {
    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
}


@Miere除非你提供零长度缓冲区或计数,"小暂停"或其他方式,否则`InputStream.read()`不可能返回零.它将阻塞,直到至少传输了一个字节或流结束或发生错误.你对`Files.copy()`内部的主张是毫无根据的.
不幸的是,如果存在重定向,例如"302 Found",则会无声地失败(下载0个字节).
尽管这是一个优雅的解决方案,但在幕后这种方法可以默默地背叛你.Files.copy(InputStream,Paths,FileOption)将复制过程委托给Files.copy(InputStream,OutputStream).最后一种方法不检查流(-1)的结尾,但检查没有字节读取(0).这意味着,如果您的网络有一点暂停,它可以读取0个字节并结束复制过程,即使该流未完成以供操作系统下载.
我有一个单元测试,读取2.6TiB的二进制文件.使用Files.copy它总是在我的HDD存储服务器(XFS)上失败,但它只失败了几次我的SSH.看看JDK 8的File.copy代码我发现它检查'> 0'以离开'while'循环.我只是用-1复制完全相同的代码,并且两个单元测试再也没有停止过.一旦InputStream可以表示网络和本地文件描述符,并且两个IO操作都受操作系统上下文切换的影响,我就无法理解为什么我的声明毫无根据.有人可能会说它运气好,但它不再令人头痛.

4> Ben Noland..:
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();
        }
    }
}

您需要处理异常,可能是此方法的外部异常.


如果`in.close`抛出异常,则不调用`fout.close`.
如何下载速度更快?喜欢下载加速器?

5> z -..:

下载文件需要您阅读它,无论哪种方式,您都必须以某种方式浏览文件.您可以直接从流中读取字节,而不是逐行读取:

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);
    }



6> Jan Nielsen..:

这是一个老问题,但这是一个优雅的JDK解决方案:

public static void download(String url, String fileName) throws Exception {
    try (InputStream in = URI.create(url).toURL().openStream()) {
        Files.copy(in, Paths.get(fileName));
    }
}

简洁,可读,适当封闭的资源,除了核心JDK和语言功能之外什么都不用.



7> BullyWiiPlaz..:

使用时Java 7+使用以下方法从Internet下载文件并将其保存到某个目录:

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;
}

文档在这里.



8> Brian Risk..:

这个答案几乎就像选择的答案,但有两个增强功能:它是一个方法,它关闭了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()`isnt'指定在一次调用中完成整个传输.这就是它返回计数的原因.你必须循环.

9> mumair..:
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`抛出异常,则不调用`out.close`.

10> belgarionthe..:

就个人而言,我发现Apache的HttpClient能够满足我对此需要做的所有事情. 这是一个关于使用HttpClient的精彩教程


commons-io也是一个很棒的图书馆

11> msangel..:

这是另一个基于Brian Risk使用try-with语句的答案的 java7变体:

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);
      }

  }

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有