Я разработал небольшой скребок Java, который собирает ссылки на нужные файлы Excel. Как загрузить эти файлы Excel через Java? [Дубликат]

Если вы используете C # 7, вы можете использовать удобный метод обертки, подобный этому ...

public static class TaskEx
{
    public static async Task<(T1, T2)> WhenAll<T1, T2>(Task<T1> task1, Task<T2> task2)
    {
        await Task.WhenAll(task1, task2);
        return (task1.Result, task2.Result);
    }
}

..., чтобы включить удобный синтаксис, подобный этому, когда вы хотите ждать нескольких задач с разными типами возврата. Конечно, вам придется сделать несколько перегрузок для разного количества задач.

var (someInt, someString) = await TaskEx.WhenAll(GetIntAsync(), GetStringAsync());
363
задан Rubens Mariuzzo 29 August 2013 в 00:38
поделиться

18 ответов

Это старый вопрос, но вот элегантное решение 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 и языка.

509
ответ дан Jan Nielsen 17 August 2018 в 11:06
поделиться
  • 1
    @willcodejavaforfood: это просто псевдоним для 16777216. Произвольный длинный размер блока. Магический калькулятор (будьте осторожны!) – dfa 28 May 2009 в 16:23
  • 2
    Закройте все три с помощью 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 & lt; 24); } – mazatwork 8 November 2012 в 11:44
  • 3
    Это будет загружать только первые 16 МБ файла: stackoverflow.com/questions/8405062/downloading-files-with-java – Ben McCann 12 January 2013 в 23:04
  • 4
    @kirdie, и если я хочу больше, чем 8388608 TB? – Cruncher 15 October 2013 в 15:02
  • 5
    Один звонок не является адекватным. transferFrom() isnt 'указан для завершения всей передачи за один раз. Вот почему он возвращает счет. Вы должны зациклиться. – user207421 23 July 2014 в 03:32

Подводя итоги (и как-то отполировать и обновлять) предыдущие ответы. Три следующих метода практически эквивалентны. (Я добавил явные тайм-ауты, потому что я думаю, что они необходимы, никто не хочет, чтобы загрузка зависала навсегда, когда соединение потеряно.)

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

Я не вижу существенных различий, все мне кажутся правдоподобными , Они безопасны и эффективны. (Различия в скорости кажутся едва ли релевантными - я пишу 180 МБ с локального сервера на SSD-диск в периоды, которые колеблются от 1,2 до 1,5 сегментов). Они не требуют внешних библиотек. Все работы с произвольными размерами и (по моему опыту) перенаправления HTTP.

Кроме того, все throw FileNotFoundException, если ресурс не найден (ошибка 404, обычно) и java.net.UnknownHostException, если ошибка DNS не удалась ; другое IOException соответствует ошибкам во время передачи.

(Помечается как wiki сообщества, не стесняйтесь добавлять информацию или исправления)

1
ответ дан 2 revs 17 August 2018 в 11:06
поделиться

Лично я нашел HttpClient Apache более чем способным ко всему, что мне нужно было сделать в отношении этого. Здесь - отличный учебник по использованию HttpClient

7
ответ дан belgariontheking 17 August 2018 в 11:06
поделиться

Если вы находитесь за прокси-сервером, вы можете установить прокси-серверы в 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();
        }
    }
0
ответ дан bpjoshi 17 August 2018 в 11:06
поделиться

Этот ответ почти точно подобен выбранному ответу, но с двумя улучшениями: это метод и он закрывает объект 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();
        }
    }
13
ответ дан Brian Risk 17 August 2018 в 11:06
поделиться
  • 1
    Вы также должны закрыть rbc. – Manuel 27 May 2015 в 13:43
  • 2
    Спасибо, Мануэль! Готово. – Brian Risk 28 May 2015 в 14:37
  • 3
    Один звонок не является адекватным. transferFrom() isnt 'указан для завершения всей передачи за один раз. Вот почему он возвращает счет. Вы должны зациклиться. – user207421 5 July 2016 в 09:30

При использовании Java 7+ используйте следующий метод для загрузки файла из Интернета и сохранения его в какой-либо каталог:

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

Документация здесь .

14
ответ дан BullyWiiPlaza 17 August 2018 в 11:06
поделиться

Вы можете сделать это в 1 строке, используя netloader для Java :

new NetFile(new File("my/zips/1.zip"), "https://example.com/example.zip", -1).load(); //returns true if succeed, otherwise false.
0
ответ дан Carrot--Show 17 August 2018 в 11:06
поделиться

Это еще один вариант 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);
      }

  }
9
ответ дан Community 17 August 2018 в 11:06
поделиться
  • 1
    Если in.close выдает исключение, out.close не вызывается. – Beryllium 9 August 2013 в 16:17
  • 2
    Один звонок не является адекватным. transferFrom() isnt 'указан для завершения всей передачи за один раз. Вот почему он возвращает счет. Вы должны зациклиться. – user207421 5 July 2016 в 09:30
  • 3
    Я не знаю, почему вы обращаетесь к этому тупому вопросу. Это не имеет никакого отношения к тому, что я сказал, и я действительно отказываюсь вставлять слова в рот. – user207421 30 July 2017 в 15:31
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;
    }
}
0
ответ дан galkin 17 August 2018 в 11:06
поделиться
  • 1
    Вы можете улучшить свой ответ, предоставив информацию о том, как работает ваш код вместо того, чтобы просто сбрасывать его. – Matej Kormuth 1 July 2017 в 22:26
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();
        }
    }
}

Вам нужно будет обрабатывать исключения, возможно, внешние для этого метода.

81
ответ дан Jared Burrows 17 August 2018 в 11:06
поделиться
  • 1
    Как скачать очень быстро? Как ускоритель загрузки? – digz6666 10 January 2012 в 09:08
  • 2
    Если in.close выдает исключение, fout.close не вызывается. – Beryllium 9 August 2013 в 16:15
  • 3
    Как показать процент загруженного – meain 10 April 2014 в 17:54
  • 4
    @ComFreek Это просто неверно. Использование BufferedInputStream имеет точно нулевой эффект на тайм-аутах сокета. Я уже опроверг это как «городской миф» в своих комментариях к «справочным данным», которые вы указали. Три года назад. – user207421 23 July 2014 в 03:33
  • 5
    @EJP Спасибо за исправление! Я удалил свой комментарий (для архива: я связал с этот ответ , в котором указано, что BufferedInputStream "может вызвать непредсказуемые сбои & quot;). – ComFreek 24 July 2014 в 16:53

Здесь много элегантных и эффективных ответов. Но краткость может заставить нас потерять какую-то полезную информацию. В частности, часто не хочется рассматривать ошибку соединения как «Исключение», и можно было бы по-разному относиться к каким-либо связанным с сетью ошибкам - например, решить, следует ли повторить загрузку.

Вот метод, который не вызывает исключения для сетевых ошибок (только для действительно исключительных проблем, таких как неверный 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;
}
2
ответ дан leonbloy 17 August 2018 в 11:06
поделиться

С помощью файла Apache HttpComponents вместо Commons-IO можно загрузить файл. Этот код позволяет загружать файл на Java в соответствии с его URL-адресом и сохранять его в определенном месте назначения.

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-Agent и Referer значения, которые имеют решающее значение для многих веб-сайтов.

1
ответ дан Mike B. 17 August 2018 в 11:06
поделиться

Существует проблема с простым использованием:

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
ответ дан oktieh 17 August 2018 в 11:06
поделиться

Используйте apache commons-io , только один код строки:

FileUtils.copyURLToFile(URL, File)
440
ответ дан Pont 17 August 2018 в 11:06
поделиться
  • 1
    Ницца! Только то, что я ищу! Я знал, что библиотеки Apache уже будут охватывать это. BTW, рекомендуется использовать перегруженную версию с параметрами тайм-аута! – Hendy Irawan 23 January 2012 в 17:11
  • 2
    ... и при использовании этой перегруженной версии помните, что таймауты указаны в миллисекундах, а не секундах. – László van den Hoek 6 July 2012 в 13:00
  • 3
    Обратите внимание, что copyURLToFile с параметром таймаута доступен только с версии 2.0 библиотеки Commons IO. См. Java docs – Stanley 12 April 2013 в 05:00
  • 4
    Это должен быть принятый ответ – Magno C 25 November 2014 в 12:38
  • 5
    что, если в запрос должен быть добавлен основной заголовок аутентификации? есть ли обходной путь? – Damian 2 April 2015 в 14:30

Упрощенное использование nio:

URL website = new URL("http://www.website.com/information.asp");
try (InputStream in = website.openStream()) {
    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
}
107
ответ дан r0estir0bbe 17 August 2018 в 11:06
поделиться
  • 1
    К сожалению, это безмолвно (загружает 0 байт) в случае, если есть перенаправление, такое как «302 Найдено». – Alexander K 9 January 2016 в 06:43
  • 2
    @AlexanderK Но почему вы вслепую скачиваете такой ресурс? – xuesheng 12 January 2016 в 19:23
  • 3
    Несмотря на то, что это изящное решение, за кулисами этот подход мог бы молча предать вас. Files.copy (InputStream, Paths, FileOption) делегирует процесс копирования в Files.copy (InputStream, OutputStream). Этот последний метод не проверяет конец потока (-1), но проверяет отсутствие байта (0). Это означает, что если ваша сеть имела небольшую паузу, она могла бы читать 0 байт и завершать процесс копирования, даже если поток не будет завершен для загрузки ОС. – Miere 13 April 2016 в 13:17
  • 4
    @Miere Невозможно, чтобы InputStream.read() возвращал ноль, если вы не предоставили буфер или счетчик нулевой длины, «небольшую паузу» или иначе. Он будет блокироваться до тех пор, пока не будет передан хотя бы один байт или конец потока или не произойдет ошибка. Ваше утверждение о внутренних функциях Files.copy() необоснованно. – user207421 5 July 2016 в 09:26
  • 5
    У меня есть единичный тест, который читает двоичный файл с 2.6TiB. Используя Files.copy, он всегда терпит неудачу на моем сервере хранения жесткого диска (XFS), но он терпит неудачу только несколько раз мой SSH. Посмотрев на JDK 8 код File.copy, я определил, что он проверяет наличие «& gt; 0 ', чтобы оставить цикл while. Я просто скопировал точно такой же код с -1, и оба модульных теста никогда не останавливались. Как только InputStream может представлять сетевые и локальные дескрипторы файлов, и обе операции ввода-вывода подвержены переключению контекста ОС, я не могу понять, почему мое требование необоснованно. Можно утверждать, что он работает удачей, но больше не болел. – Miere 6 July 2016 в 16:50

Ниже приведен пример кода для загрузки фильма из Интернета с помощью 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);
    }
0
ответ дан Sachin Rane 17 August 2018 в 11:06
поделиться
  • 1
    Как правило, ответы гораздо полезнее, если они включают объяснение того, что должен делать код, и почему это решает проблему, не представляя других. – Tim Diekmann 27 May 2018 в 11:18

Загрузка файла требует, чтобы вы его прочитали, в любом случае вам придется каким-то образом пройти через файл. Вместо строки за строкой вы можете просто прочитать ее байтами из потока:

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);
    }
22
ответ дан Uku Loskit 17 August 2018 в 11:06
поделиться

В библиотеке underscore-java имеется метод U.fetch (url).

pom.xml:

  <groupId>com.github.javadev</groupId>
  <artifactId>underscore</artifactId>
  <version>1.35</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();
    }
}
1
ответ дан Valentyn Kolesnikov 17 August 2018 в 11:06
поделиться
  • 1
    Насколько полезен этот ответ, когда ссылка становится недействительной? Посмотрите на Как ответить – JimHawkins 25 July 2017 в 08:10
  • 2
    Код не будет компилироваться. Задайте вопрос в Java, но ваш ответ выглядит как JavaScript – talex 25 July 2017 в 12:10
  • 3
    @talex Я добавил раздел pom.xml и улучшенный пример кода. – Valentyn Kolesnikov 30 July 2017 в 10:19
Другие вопросы по тегам:

Похожие вопросы: