首页 文章

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

提问于
浏览
382

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

20 回答

  • 14

    这是另一个基于Brian Risk's answer的java7变体,使用了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);
          }
    
      }
    
  • 1

    试试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()potentially 比从源通道读取并写入此通道的简单循环更有效 . 许多操作系统可以直接从源通道将字节传输到文件系统缓存中,而无需实际复制它们 .

    查看更多相关信息here .

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

  • 9

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

    FileUtils.copyURLToFile(URL, File)
    
  • 5

    更简单的nio用法:

    URL website = new URL("http://www.website.com/information.asp");
    try (InputStream in = website.openStream()) {
        Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
    }
    
  • 112
    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();
            }
        }
    }
    

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

  • 1

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

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

    这个答案几乎就像选择的答案,但有两个增强功能:它是一个方法,它关闭了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();
            }
        }
    
  • 14

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

    文档here .

  • 2

    这是一个老问题,但这是一个优雅的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和语言功能之外什么都不用 .

  • 0
    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]);
            }
        }
    }
    
  • 528

    就个人而言,我发现Apache's HttpClient能够满足我对此需要做的所有事情 . Here是一个使用HttpClient的好教程

  • 22

    这里有许多优雅而有效的答案 . 但简洁可能会让我们失去一些有用的信息 . 特别是,一个人可能想要区别对待某种与网络相关的错误 - 例如,决定是否应该重试下载 .

    这是一个不会为网络错误抛出异常的方法(仅针对真正异常的问题,因为格式错误的URL或写入文件的问题)

    /**
     * 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;
    }
    
  • 14

    简单使用有一个问题:

    org.apache.commons.io.FileUtils.copyURLToFile(URL, File)
    

    如果您需要下载并保存非常大的文件,或者通常如果您需要自动重试,以防连接断开 .

    在这种情况下我建议的是Apache HttpClient以及org.apache.commons.io.FileUtils . 例如:

    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();
    }
    
  • 1

    它's possible to download the file with with Apache' s HttpComponents 而不是 Commons-IO . 此代码允许您根据URL下载Java文件并将其保存在特定目标位置 .

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

    与单行代码形成对比:

    FileUtils.copyURLToFile(fileURL, new File(fileSavePath),
                            URLS_FETCH_TIMEOUT, URLS_FETCH_TIMEOUT);
    

    此代码将为您提供对进程的更多控制,并且不仅可以指定超时,还可以指定 User-AgentReferer 值,这对许多网站都很重要 .

  • 0

    总结(并以某种方式抛光和更新)以前的答案 . 以下三种方法实际上是等同的 . (我添加了显式超时,因为我认为它们是必须的,当连接丢失时,没有人希望下载永远冻结 . )

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

    我没有发现显着的差异,对我来说都是正确的 . 它们安全有效 . (速度上的差异似乎不太相关 - 我在本地服务器上写入180Mb到SSD磁盘的时间波动在1.2到1.5左右) . 它们不需要外部库 . 所有工作都具有任意大小和(根据我的经验)HTTP重定向 .

    此外,如果找不到资源,则全部抛出 FileNotFoundException (通常是错误404),如果DNS解析失败,则抛出 java.net.UnknownHostException ;其他IOException对应于传输过程中的错误 .

    (标记为社区维基,随时添加信息或更正)

  • 0

    underscore-java库中有方法U.fetch(url) .

    pom.xml中:

    <groupId>com.github.javadev</groupId>
      <artifactId>underscore</artifactId>
      <version>1.36</version>
    

    代码示例:

    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();
        }
    }
    
  • 452
    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;
        }
    }
    
  • 7

    您可以使用netloader for Java在1行中执行此操作:

    new NetFile(new File("my/zips/1.zip"), "https://example.com/example.zip", -1).load(); //returns true if succeed, otherwise false.
    
  • 0

    如果您在代理后面,可以在java程序中设置代理,如下所示:

    Properties systemSettings = System.getProperties();
            systemSettings.put("proxySet", "true");
            systemSettings.put("https.proxyHost", "https proxy of your org");
            systemSettings.put("https.proxyPort", "8080");
    

    如果您不在代理服务器后面,请不要在代码中包含上面的行 . 当您在代理后面时下载文件的完整工作代码 .

    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();
            }
        }
    
  • 83

    以下是使用java代码从Internet下载电影的示例代码:

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

相关问题