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();
// ...

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

BalusC
источник
2
Знаете ли вы, делает ли это сетевой запрос при каждом чтении InputStream или он читает весь файл сразу, чтобы не приходилось делать сетевые запросы при чтении?
gsingh2011 05
Вызов этого метода в потоке пользовательского интерфейса в Android вызовет исключение. Сделайте это в фоновом потоке. Use Bolts-Android
Behrouz.M
19

Пытаться:

final InputStream is = new URL("http://wwww.somewebsite.com/a.txt").openStream();
whiskeysierra
источник
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);
    }
jschnasse
источник
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-форму. Это взято из моего учебника по этой теме.

Ян Боднар
источник