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

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

Виклик цього методу в потоці інтерфейсу користувача в Android призведе до виключення. Зробіть це у фоновій нитці. Використовуйте Bolts-Android
Behrouz.M


10

(а) wwww.somewebsite.com/a.txtне є "URL-адресою файлу". Це зовсім не URL-адреса. Якщо ви поставите http://на передній частині, це буде HTTP-адреса, що явно ви тут маєте намір.

(b) 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уже йде переадресація за замовчуванням, як я вже заявив.
Маркіз Лорн

@ 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>  

Це залежності Мейвена. Ми використовуємо бібліотеку 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.