InputStream из URL


117

Как получить InputStream из URL-адреса?

например, я хочу взять файл по URL-адресу wwww.somewebsite.com/a.txtи прочитать его как InputStream в Java через сервлет.

я пробовал

InputStream is = new FileInputStream("wwww.somewebsite.com/a.txt");

но я получил ошибку:

java.io.FileNotFoundException

1
Почему откатили удаление servletsтега? Здесь нет javax.servlet.*API. У вас возникнет точно такая же проблема, если вы сделаете это в обычном Java-классе с main()методом.
— BalusC 03

1
Возможно, вам стоит ознакомиться с тем, что такое URL: docs.oracle.com/javase/tutorial/networking/urls/definition.html
— b1nary.atr0phy

Ответы:


228

Используйте java.net.URL#openStream()правильный URL (включая протокол!). Например

InputStream input = new URL("http://www.somewebsite.com/a.txt").openStream();
// ...

Смотрите также:


2
Знаете ли вы, делает ли это сетевой запрос при каждом чтении InputStream или он читает весь файл сразу, чтобы не приходилось делать сетевые запросы при чтении?
— gsingh2011 05

Вызов этого метода в потоке пользовательского интерфейса в Android вызовет исключение. Сделайте это в фоновом потоке. Use Bolts-Android
— Behrouz.M


10

(а) wwww.somewebsite.com/a.txtне является «URL-адресом файла». Это вообще не URL. Если вы поместите http://его спереди, это будет URL-адрес HTTP, что явно то, что вы здесь имеете в виду.

(б) FileInputStreamпредназначен для файлов, а не для URL-адресов.

(c) Способ получения входного потока с любого URL-адреса - через URL.openStream(),или URL.getConnection().getInputStream(),что-то подобное, но у вас могут быть другие причины, чтобы URLConnectionсначала получить и поиграть с ним.


4

В исходном коде используется FileInputStream, предназначенный для доступа к файлам, размещенным в файловой системе.

Используемый вами конструктор попытается найти файл с именем a.txt в подпапке www.somewebsite.com текущего рабочего каталога (значение системного свойства user.dir). Введенное вами имя преобразуется в файл с использованием класса File.

Объекты URL - это общий способ решить эту проблему. Вы можете использовать URL-адреса для доступа к локальным файлам, а также к ресурсам, размещенным в сети. Класс URL поддерживает протокол file: //, кроме http: // или https: //, так что все готово.


2

Чистая Java:

 urlToInputStream(url,httpHeaders);

С некоторым успехом использую этот метод. Он обрабатывает перенаправления, и можно передавать переменное количество заголовков HTTP как Map<String,String>. Он также позволяет перенаправлять с HTTP на HTTPS .

private InputStream urlToInputStream(URL url, Map<String, String> args) {
    HttpURLConnection con = null;
    InputStream inputStream = null;
    try {
        con = (HttpURLConnection) url.openConnection();
        con.setConnectTimeout(15000);
        con.setReadTimeout(15000);
        if (args != null) {
            for (Entry<String, String> e : args.entrySet()) {
                con.setRequestProperty(e.getKey(), e.getValue());
            }
        }
        con.connect();
        int responseCode = con.getResponseCode();
        /* By default the connection will follow redirects. The following
         * block is only entered if the implementation of HttpURLConnection
         * does not perform the redirect. The exact behavior depends to 
         * the actual implementation (e.g. sun.net).
         * !!! Attention: This block allows the connection to 
         * switch protocols (e.g. HTTP to HTTPS), which is <b>not</b> 
         * default behavior. See: /programming/1884230 
         * for more info!!!
         */
        if (responseCode < 400 && responseCode > 299) {
            String redirectUrl = con.getHeaderField("Location");
            try {
                URL newUrl = new URL(redirectUrl);
                return urlToInputStream(newUrl, args);
            } catch (MalformedURLException e) {
                URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl);
                return urlToInputStream(newUrl, args);
            }
        }
        /*!!!!!*/

        inputStream = con.getInputStream();
        return inputStream;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Полный пример вызова

private InputStream getInputStreamFromUrl(URL url, String user, String passwd) throws IOException {
        String encoded = Base64.getEncoder().encodeToString((user + ":" + passwd).getBytes(StandardCharsets.UTF_8));
        Map<String,String> httpHeaders=new Map<>();
        httpHeaders.put("Accept", "application/json");
        httpHeaders.put("User-Agent", "myApplication");
        httpHeaders.put("Authorization", "Basic " + encoded);
        return urlToInputStream(url,httpHeaders);
    }

HttpURLConnectionуже будет следовать перенаправлениям, если вы не скажете ему не делать этого, чего вы не сделали.
— Маркиз Лорн

1
Я знаю, что OP не упоминал заголовки, но я ценю лаконичный (ну, учитывая Java) пример.
— chbrown

@EJP Я добавил некоторые пояснения в виде встроенного комментария. Думаю, я в основном ввел блок перенаправления для случая, когда HTTP 301 перенаправляет HTTP-адрес на HTTPS-адрес. Конечно, это выходит за рамки исходного вопроса, но это общий вариант использования, который не обрабатывается реализацией по умолчанию. См .: stackoverflow.com/questions/1884230/…
— jschnasse

Ваш код одинаково хорошо работает без блока перенаправления, поскольку HttpURLConnection, как я уже сказал, перенаправления уже выполняются по умолчанию.
— Marquis of Lorne

@ user207421 Это отчасти верно. Блок перенаправления предназначен для переключения протоколов, например http-> https, который по умолчанию не поддерживается. Я попытался выразить это в комментарии в коде. См. Stackoverflow.com/questions/1884230/… .
— jschnasse

-1

Вот полный пример, который читает содержимое данной веб-страницы. Веб-страница читается из HTML-формы. Мы используем стандартные InputStreamклассы, но это проще сделать с помощью библиотеки JSoup.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>

</dependency>

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.6</version>
</dependency>  

Это зависимости Maven. Мы используем библиотеку Apache Commons для проверки строк URL.

package com.zetcode.web;

import com.zetcode.service.WebPageReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ReadWebPage", urlPatterns = {"/ReadWebPage"})
public class ReadWebpage extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        String page = request.getParameter("webpage");

        String content = new WebPageReader().setWebPageName(page).getWebPageContent();

        ServletOutputStream os = response.getOutputStream();
        os.write(content.getBytes(StandardCharsets.UTF_8));
    }
}

ReadWebPageСервлета считывает содержимое данного веб - страницы и отправляет его обратно клиенту в текстовом формате. Задача чтения страницы делегирована WebPageReader.

package com.zetcode.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.commons.validator.routines.UrlValidator;

public class WebPageReader {

    private String webpage;
    private String content;

    public WebPageReader setWebPageName(String name) {

        webpage = name;
        return this;
    }

    public String getWebPageContent() {

        try {

            boolean valid = validateUrl(webpage);

            if (!valid) {

                content = "Invalid URL; use http(s)://www.example.com format";
                return content;
            }

            URL url = new URL(webpage);

            try (InputStream is = url.openStream();
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(is, StandardCharsets.UTF_8))) {

                content = br.lines().collect(
                      Collectors.joining(System.lineSeparator()));
            }

        } catch (IOException ex) {

            content = String.format("Cannot read webpage %s", ex);
            Logger.getLogger(WebPageReader.class.getName()).log(Level.SEVERE, null, ex);
        }

        return content;
    }

    private boolean validateUrl(String webpage) {

        UrlValidator urlValidator = new UrlValidator();

        return urlValidator.isValid(webpage);
    }
}

WebPageReaderпроверяет URL-адрес и читает содержимое веб-страницы. Он возвращает строку, содержащую HTML-код страницы.

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <form action="ReadWebPage">

            <label for="page">Enter a web page name:</label>
            <input  type="text" id="page" name="webpage">

            <button type="submit">Submit</button>

        </form>
    </body>
</html>

Наконец, это домашняя страница, содержащая HTML-форму. Это взято из моего учебника по этой теме.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.