InputStream de um URL


117

Como obtenho um InputStream de um URL?

por exemplo, quero pegar o arquivo no url wwww.somewebsite.com/a.txte lê-lo como um InputStream em Java, por meio de um servlet.

eu tentei

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

mas o que recebi foi um erro:

java.io.FileNotFoundException

1
Por que você reverteu a remoção da servletstag? Não há javax.servlet.*API envolvida aqui. Você teria exatamente o mesmo problema ao fazer isso em uma classe Java simples com um main()método.
— BalusC

1
Talvez você deva se familiarizar com o que é um URL: docs.oracle.com/javase/tutorial/networking/urls/definition.html
— b1nary.atr0phy

Respostas:


228

Use java.net.URL#openStream()com um URL adequado (incluindo o protocolo!). Por exemplo

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

Veja também:


2
Você sabe se isso faz uma solicitação de rede em cada leitura do InputStream ou se ele lê o arquivo inteiro de uma vez para não ter que fazer solicitações de rede nas leituras?
— gsingh2011

Chamar esse método no thread de IU no Android gerará uma exceção. Faça isso em um tópico de fundo. Use Bolts-Android
— Behrouz.M

19

Experimentar:

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

10

(a) wwww.somewebsite.com/a.txtnão é um 'URL de arquivo'. Não é um URL. Se você colocasse http://na frente, seria uma URL HTTP, que é claramente o que você pretende aqui.

(b) FileInputStreamé para arquivos, não URLs.

(c) A maneira de obter um fluxo de entrada de qualquer URL é via URL.openStream(),ou URL.getConnection().getInputStream(),equivalente, mas você pode ter outros motivos para obter URLConnectione brincar com ele primeiro.


4

Seu código original usa FileInputStream, que é para acessar arquivos hospedados do sistema de arquivos.

O construtor usado tentará localizar um arquivo denominado a.txt na subpasta www.somewebsite.com do diretório de trabalho atual (o valor da propriedade do sistema user.dir). O nome fornecido é resolvido para um arquivo usando a classe File.

Objetos de URL são a maneira genérica de resolver isso. Você pode usar URLs para acessar arquivos locais, mas também recursos hospedados na rede. A classe URL suporta o protocolo file: // além de http: // ou https: //, então você está pronto para começar.


2

Java puro:

 urlToInputStream(url,httpHeaders);

Com algum sucesso, uso esse método. Ele lida com redirecionamentos e pode-se passar um número variável de cabeçalhos HTTP como Map<String,String>. Ele também permite redirecionamentos de HTTP para 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);
    }
}

Exemplo completo de chamada

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

HttpURLConnectionjá seguirá os redirecionamentos, a menos que você diga para não fazer isso, o que você não fez.
— Marquês de Lorne

1
Sei que o OP não mencionou cabeçalhos, mas agradeço o exemplo sucinto (bem, considerando que é Java).
— chbrown

@EJP Eu adicionei alguma explicação como comentário embutido. Acho que apresentei principalmente o bloco de redirecionamento para o caso em que o HTTP 301 redireciona um endereço HTTP para um endereço HTTPS. Claro, isso vai além da questão original, mas é um caso de uso comum que não é tratado pela implementação padrão. Consulte: stackoverflow.com/questions/1884230/…
— jschnasse

Seu código funciona igualmente bem sem o bloco de redirecionamento, pois HttpURLConnectionjá segue redirecionamentos por padrão, como já disse.
— Marquês de Lorne

@ user207421 Isso está parcialmente correto. O bloco de redirecionamento é para switches de protocolo como http-> https, que não é compatível por padrão. Tentei expressar isso no comentário no código. Consulte stackoverflow.com/questions/1884230/… .
— jschnasse

-1

Aqui está um exemplo completo que lê o conteúdo de uma determinada página da web. A página da web é lida a partir de um formulário HTML. Usamos InputStreamclasses padrão , mas isso poderia ser feito mais facilmente com a biblioteca 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>  

Essas são as dependências do Maven. Usamos a biblioteca Apache Commons para validar strings de 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));
    }
}

O ReadWebPageservlet lê o conteúdo de determinada página da web e o envia de volta ao cliente em formato de texto simples. A tarefa de ler a página é delegada 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);
    }
}

WebPageReadervalida o URL e lê o conteúdo da página da web. Ele retorna uma string contendo o código HTML da página.

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

Finalmente, esta é a página inicial que contém o formulário HTML. Isso foi tirado do meu tutorial sobre este tópico.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.