InputStream da un URL


117

Come ottengo un InputStream da un URL?

ad esempio, voglio prendere il file all'URL wwww.somewebsite.com/a.txte leggerlo come InputStream in Java, tramite un servlet.

ho provato

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

ma quello che ho ottenuto è stato un errore:

java.io.FileNotFoundException

1
Perché hai ripristinato la rimozione del servletstag? Non ci sono javax.servlet.*API coinvolte qui. Avresti esattamente lo stesso problema se lo facessi in una semplice classe Java con un main()metodo.
BalusC

1
Forse dovresti familiarizzare con cos'è un URL: docs.oracle.com/javase/tutorial/networking/urls/definition.html
b1nary.atr0phy

Risposte:


228

Utilizzare java.net.URL#openStream()con un URL appropriato (incluso il protocollo!). Per esempio

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

Guarda anche:


2
Sai se questo fa una richiesta di rete su ogni lettura di InputStream o se legge l'intero file in una volta in modo da non dover effettuare richieste di rete sulle letture?
gsingh2011

La chiamata a questo metodo nel thread dell'interfaccia utente in Android genererà un'eccezione. Fallo in un thread in background. Usa Bolts-Android
Behrouz.M

19

Provare:

final InputStream is = new URL("http://wwww.somewebsite.com/a.txt").openStream();

10

(a) wwww.somewebsite.com/a.txtnon è un "URL di file". Non è affatto un URL. Se lo metti http://davanti sarebbe un URL HTTP, che è chiaramente quello che intendi qui.

(b) FileInputStreamè per i file, non per gli URL.

(c) Il modo per ottenere un flusso di input da qualsiasi URL è tramite URL.openStream(),o URL.getConnection().getInputStream(),che è equivalente, ma potresti avere altri motivi per ottenere URLConnectione giocare prima con esso.


4

Il codice originale utilizza FileInputStream, che consente di accedere ai file ospitati nel file system.

Il costruttore utilizzato tenterà di individuare un file denominato a.txt nella sottocartella www.somewebsite.com della directory di lavoro corrente (il valore della proprietà di sistema user.dir). Il nome fornito viene risolto in un file utilizzando la classe File.

Gli oggetti URL sono il modo generico per risolvere questo problema. È possibile utilizzare gli URL per accedere ai file locali ma anche alle risorse ospitate in rete. La classe URL supporta il protocollo file: // oltre a http: // o https: //, quindi sei a posto.


2

Java puro:

 urlToInputStream(url,httpHeaders);

Con un certo successo utilizzo questo metodo. Esso gestisce redirect e si può passare un numero variabile di intestazioni HTTP come Map<String,String>. Consente anche i reindirizzamenti da HTTP a 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);
    }
}

Chiamata di esempio completa

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

HttpURLConnectionseguirà già i reindirizzamenti a meno che tu non gli dica di non farlo, cosa che non hai fatto.
Marchese di Lorne

1
So che OP non ha menzionato le intestazioni ma apprezzo l'esempio succinto (beh, considerando che è Java).
chbrown

@EJP ho aggiunto alcune spiegazioni come commento in linea. Penso di aver introdotto principalmente il blocco di reindirizzamento per il caso in cui HTTP 301 reindirizza un indirizzo HTTP a un indirizzo HTTPS. Naturalmente, questo va oltre la domanda originale, ma è un caso d'uso comune che non viene gestito dall'implementazione predefinita. Vedi: stackoverflow.com/questions/1884230/...
jschnasse

Il tuo codice funziona altrettanto bene senza il blocco di reindirizzamento, poiché HttpURLConnectiongià segue i reindirizzamenti di default, come ho già affermato.
Marchese di Lorne

@ user207421 Questo è parzialmente corretto. Il blocco di reindirizzamento è per le opzioni di protocollo come http-> https che non è supportato per impostazione predefinita. Ho provato a esprimerlo nel commento nel codice. Vedi stackoverflow.com/questions/1884230/… .
jschnasse

-1

Ecco un esempio completo che legge i contenuti di una data pagina web. La pagina web viene letta da un modulo HTML. Usiamo InputStreamclassi standard , ma potrebbe essere fatto più facilmente con la libreria 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>  

Queste sono le dipendenze di Maven. Usiamo la libreria Apache Commons per convalidare le stringhe 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));
    }
}

Il ReadWebPageservlet legge il contenuto della pagina web data e lo invia al client in formato testo normale. Il compito di leggere la pagina è delegato a 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);
    }
}

WebPageReaderconvalida l'URL e legge i contenuti della pagina web. Restituisce una stringa contenente il codice HTML della pagina.

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

Infine, questa è la home page contenente il modulo HTML. Questo è tratto dal mio tutorial su questo argomento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.