InputStream von einer URL

117

Wie erhalte ich einen InputStream von einer URL?

Zum Beispiel möchte ich die Datei unter der URL nehmen wwww.somewebsite.com/a.txtund sie als InputStream in Java über ein Servlet lesen.

ich habe es versucht

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

aber was ich bekam war ein Fehler:

java.io.FileNotFoundException
Weißer Bär
quelle
1
Warum haben Sie das Entfernen des servletsTags rückgängig gemacht? Hier ist keine javax.servlet.*API beteiligt. Sie hätten genau das gleiche Problem, wenn Sie dies in einer einfachen Vanille-Java-Klasse mit einer main()Methode tun würden .
BalusC
1
Vielleicht sollten Sie sich mit einer URL vertraut machen: docs.oracle.com/javase/tutorial/networking/urls/definition.html
b1nary.atr0phy

Antworten:

228

Verwenden Sie java.net.URL#openStream()mit einer richtigen URL (einschließlich des Protokolls!). Z.B

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

Siehe auch:

BalusC
quelle
2
Wissen Sie, ob dies bei jedem Lesevorgang des InputStream eine Netzwerkanforderung stellt oder ob die gesamte Datei auf einmal gelesen wird, damit beim Lesen keine Netzwerkanforderungen gestellt werden müssen?
Gsingh2011
Das Aufrufen dieser Methode im UI-Thread in Android löst eine Ausnahme aus. Mach es in einem Hintergrund-Thread. Verwenden Sie Bolts-Android
Behrouz.M
19

Versuchen:

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

(a) wwww.somewebsite.com/a.txtist keine 'Datei-URL'. Es ist überhaupt keine URL. Wenn Sie http://die Vorderseite einfügen, handelt es sich um eine HTTP-URL, die Sie hier eindeutig beabsichtigen.

(b) FileInputStreamgilt für Dateien, nicht für URLs.

(c) Der Weg, um einen Eingabestream von einer beliebigen URL abzurufen, ist über URL.openStream(),oder URL.getConnection().getInputStream(),gleichwertig, aber Sie haben möglicherweise andere Gründe, den zu erhalten URLConnectionund zuerst damit zu spielen.

Marquis von Lorne
quelle
4

Ihr ursprünglicher Code verwendet FileInputStream, um auf vom Dateisystem gehostete Dateien zuzugreifen.

Der von Ihnen verwendete Konstruktor versucht, eine Datei mit dem Namen a.txt im Unterordner www.somewebsite.com des aktuellen Arbeitsverzeichnisses zu finden (der Wert der Systemeigenschaft user.dir). Der von Ihnen angegebene Name wird mithilfe der File-Klasse in eine Datei aufgelöst.

URL-Objekte sind der generische Weg, um dies zu lösen. Sie können URLs verwenden, um auf lokale Dateien, aber auch auf im Netzwerk gehostete Ressourcen zuzugreifen. Die URL-Klasse unterstützt neben http: // oder https: // das Protokoll file: //, sodass Sie loslegen können.

Cristian Botiza
quelle
2

Reines Java:

 urlToInputStream(url,httpHeaders);

Mit einigem Erfolg verwende ich diese Methode. Es behandelt Weiterleitungen und man kann eine variable Anzahl von HTTP-Headern als übergeben Map<String,String>. Es ermöglicht auch Weiterleitungen von HTTP zu 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);
    }
}

Vollständiger Beispielaufruf

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
quelle
HttpURLConnectionwird bereits Weiterleitungen folgen, es sei denn, Sie sagen es nicht, was Sie nicht haben.
Marquis von Lorne
1
Ich weiß, dass OP keine Header erwähnt hat, aber ich schätze das prägnante Beispiel (wenn man bedenkt, dass es Java ist).
Chbrown
@EJP Ich habe eine Erklärung als Inline-Kommentar hinzugefügt. Ich denke, ich habe hauptsächlich den Umleitungsblock für den Fall eingeführt, dass HTTP 301 eine HTTP-Adresse zu einer HTTPS-Adresse umleitet. Dies geht natürlich über die ursprüngliche Frage hinaus, ist jedoch ein häufiger Anwendungsfall, der von der Standardimplementierung nicht behandelt wird. Siehe: stackoverflow.com/questions/1884230/…
jschnasse
Ihr Code funktioniert ohne den Umleitungsblock genauso gut, wie HttpURLConnectionbereits erwähnt, wie bereits erwähnt.
Marquis von Lorne
@ user207421 Dies ist teilweise richtig. Der Umleitungsblock ist für Protokollschalter wie http-> https vorgesehen, die standardmäßig nicht unterstützt werden. Ich habe versucht, dies im In-Code-Kommentar auszudrücken. Siehe stackoverflow.com/questions/1884230/… .
jschnasse
-1

Hier ist ein vollständiges Beispiel, das den Inhalt der angegebenen Webseite liest. Die Webseite wird aus einem HTML-Formular gelesen. Wir verwenden Standardklassen InputStream, aber mit der JSoup-Bibliothek könnte dies einfacher sein.

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

Dies sind die Maven-Abhängigkeiten. Wir verwenden die Apache Commons-Bibliothek, um URL-Zeichenfolgen zu überprüfen.

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

Das ReadWebPageServlet liest den Inhalt der angegebenen Webseite und sendet ihn im Nur-Text-Format an den Client zurück. Die Aufgabe des Lesens der Seite wird an delegiert 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Überprüft die URL und liest den Inhalt der Webseite. Es wird eine Zeichenfolge zurückgegeben, die den HTML-Code der Seite enthält.

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

Schließlich ist dies die Homepage, die das HTML-Formular enthält. Dies stammt aus meinem Tutorial zu diesem Thema.

Jan Bodnar
quelle