InputStream à partir d'une URL

117

Comment obtenir un InputStream à partir d'une URL?

par exemple, je veux prendre le fichier à l'url wwww.somewebsite.com/a.txtet le lire comme un InputStream en Java, via un servlet.

J'ai essayé

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

mais ce que j'ai obtenu était une erreur:

java.io.FileNotFoundException
Ours blanc
la source
1
Pourquoi avez-vous annulé la suppression de la servletsbalise? Il n'y a pas d' javax.servlet.*API impliquée ici. Vous auriez exactement le même problème en le faisant dans une classe Java simple avec une main()méthode.
BalusC
1
Peut-être devriez-vous vous familiariser avec ce qu'est une URL: docs.oracle.com/javase/tutorial/networking/urls/definition.html
b1nary.atr0phy

Réponses:

228

Utilisez java.net.URL#openStream()avec une URL appropriée (y compris le protocole!). Par exemple

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

Voir également:

BalusC
la source
2
Savez-vous si cela fait une requête réseau à chaque lecture de InputStream ou s'il lit le fichier entier à la fois pour ne pas avoir à faire de requêtes réseau sur les lectures?
gsingh2011
L'appel de cette méthode dans le thread d'interface utilisateur sous Android lèvera une exception. Faites-le dans un fil d'arrière-plan. Utilisez Bolts-Android
Behrouz.M
19

Essayer:

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

(a) wwww.somewebsite.com/a.txtn'est pas une 'URL de fichier'. Ce n'est pas du tout une URL. Si vous le mettez http://en avant, ce serait une URL HTTP, ce qui est clairement ce que vous prévoyez ici.

(b) FileInputStreamconcerne les fichiers, pas les URL.

(c) Le moyen d'obtenir un flux d'entrée à partir de n'importe quelle URL est via URL.openStream(),ou URL.getConnection().getInputStream(),qui est équivalent, mais vous pourriez avoir d'autres raisons d'obtenir le URLConnectionet de jouer avec d'abord.

Marquis de Lorne
la source
4

Votre code d'origine utilise FileInputStream, qui permet d'accéder aux fichiers hébergés dans le système de fichiers.

Le constructeur que vous avez utilisé tentera de localiser un fichier nommé a.txt dans le sous-dossier www.somewebsite.com du répertoire de travail actuel (la valeur de la propriété système user.dir). Le nom que vous fournissez est résolu en fichier à l'aide de la classe File.

Les objets URL sont le moyen générique de résoudre ce problème. Vous pouvez utiliser des URL pour accéder aux fichiers locaux mais également aux ressources hébergées sur le réseau. La classe URL prend en charge le protocole file: // en plus de http: // ou https: // donc vous êtes prêt à partir.

Cristian Botiza
la source
2

Java pur:

 urlToInputStream(url,httpHeaders);

Avec un certain succès, j'utilise cette méthode. Il gère les redirections et on peut passer un nombre variable d' en-têtes HTTP comme Map<String,String>. Il permet également les redirections de HTTP vers 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);
    }
}

Exemple d'appel complet

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
la source
HttpURLConnectionsuivra déjà les redirections à moins que vous ne lui disiez de ne pas le faire, ce que vous n'avez pas fait.
Marquis de Lorne
1
Je sais qu'OP n'a pas mentionné les en-têtes mais j'apprécie l'exemple succinct (enfin, étant donné que c'est Java).
chbrown
@EJP J'ai ajouté quelques explications en tant que commentaire en ligne. Je pense que j'ai principalement introduit le bloc de redirection pour le cas où HTTP 301 redirige une adresse HTTP vers une adresse HTTPS. Bien sûr, cela va au-delà de la question initiale, mais c'est un cas d'utilisation courant qui n'est pas géré par l'implémentation par défaut. Voir: stackoverflow.com/questions/1884230/…
jschnasse
Votre code fonctionne également bien sans le bloc de redirection, comme HttpURLConnectionsuit déjà les redirections par défaut, comme je l'ai déjà dit.
Marquis of Lorne
@ user207421 C'est en partie correct. Le bloc de redirection concerne les commutateurs de protocole comme http-> https qui n'est pas pris en charge par défaut. J'ai essayé d'exprimer cela dans le commentaire dans le code. Voir stackoverflow.com/questions/1884230/… .
jschnasse
-1

Voici un exemple complet qui lit le contenu de la page Web donnée. La page Web est lue à partir d'un formulaire HTML. Nous utilisons des InputStreamclasses standard , mais cela pourrait être fait plus facilement avec la bibliothèque 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>  

Ce sont les dépendances Maven. Nous utilisons la bibliothèque Apache Commons pour valider les chaînes d'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));
    }
}

Le ReadWebPageservlet lit le contenu de la page Web donnée et le renvoie au client au format texte brut. La tâche de lecture de la page est déléguée à 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);
    }
}

WebPageReadervalide l'URL et lit le contenu de la page Web. Il renvoie une chaîne contenant le code HTML de la page.

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

Enfin, c'est la page d'accueil contenant le formulaire HTML. Ceci est tiré de mon tutoriel sur ce sujet.

Jan Bodnar
la source