InputStream dari URL

117

Bagaimana cara mendapatkan InputStream dari URL?

misalnya, saya ingin mengambil file di url wwww.somewebsite.com/a.txtdan membacanya sebagai InputStream di Java, melalui servlet.

Saya sudah mencoba

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

tapi yang saya dapatkan adalah kesalahan:

java.io.FileNotFoundException
Shirohige
sumber
1
Mengapa Anda membatalkan penghapusan servletstag? Tidak ada javax.servlet.*API yang terlibat di sini. Anda akan memiliki masalah yang persis sama saat melakukannya di kelas Java vanilla biasa dengan sebuah main()metode.
BalusC
1
Mungkin Anda harus membiasakan diri dengan apa itu URL: docs.oracle.com/javase/tutorial/networking/urls/definition.html
b1nary.atr0phy

Jawaban:

228

Gunakan java.net.URL#openStream()dengan URL yang tepat (termasuk protokolnya!). Misalnya

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

Lihat juga:

BalusC
sumber
2
Apakah Anda tahu jika ini membuat permintaan jaringan pada setiap pembacaan InputStream atau apakah ia membaca seluruh file sekaligus sehingga tidak perlu membuat permintaan jaringan saat dibaca?
gsingh2011
Memanggil metode ini di UI thread di Android akan memunculkan pengecualian. Lakukan di thread latar belakang. Gunakan Bolts-Android
Behrouz.M
19

Mencoba:

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

(a) wwww.somewebsite.com/a.txtbukan 'URL file'. Ini sama sekali bukan URL. Jika Anda meletakkan http://di depannya, itu akan menjadi URL HTTP, yang jelas-jelas Anda maksudkan di sini.

(b) FileInputStreamuntuk file, bukan URL.

(c) Cara untuk mendapatkan aliran input dari URL mana pun adalah melalui URL.openStream(),atau URL.getConnection().getInputStream(),yang setara, tetapi Anda mungkin memiliki alasan lain untuk mendapatkan URLConnectiondan memainkannya terlebih dahulu.

Marquis dari Lorne
sumber
4

Kode asli Anda menggunakan FileInputStream, yang untuk mengakses file yang dihosting sistem file.

Konstruktor yang Anda gunakan akan mencoba mencari file bernama a.txt di subfolder www.somewebsite.com dari direktori kerja saat ini (nilai properti sistem user.dir). Nama yang Anda berikan diselesaikan ke file menggunakan kelas File.

Objek URL adalah cara umum untuk menyelesaikan ini. Anda dapat menggunakan URL untuk mengakses file lokal tetapi juga sumber daya yang dihosting jaringan. Kelas URL mendukung protokol file: // selain http: // atau https: // jadi Anda siap melakukannya.

Cristian Botiza
sumber
2

Java Murni:

 urlToInputStream(url,httpHeaders);

Dengan beberapa keberhasilan saya menggunakan metode ini. Ini menangani pengalihan dan seseorang dapat meneruskan sejumlah variabel dari header HTTP sebagai Map<String,String>. Ini juga memungkinkan pengalihan dari HTTP ke 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);
    }
}

Contoh panggilan lengkap

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.dll
sumber
HttpURLConnectionsudah akan mengikuti pengalihan kecuali Anda menyuruhnya untuk tidak, yang belum Anda lakukan.
Marquis dari Lorne
1
Saya tahu OP tidak menyebutkan tajuk tetapi saya menghargai contoh ringkas (yah, mengingat itu Jawa).
chbrown
@EJP Saya menambahkan beberapa penjelasan sebagai komentar inline. Saya pikir, saya terutama memperkenalkan blok pengalihan untuk kasus ketika HTTP 301 mengalihkan alamat HTTP ke alamat HTTPS. Tentu saja, ini melampaui pertanyaan awal, tetapi merupakan kasus penggunaan umum yang tidak ditangani oleh implementasi default. Lihat: stackoverflow.com/questions/1884230/…
jschnasse
Kode Anda bekerja sama baiknya tanpa blok redirect, karena HttpURLConnectionsudah mengikuti redirect secara default, seperti yang sudah saya nyatakan.
Marquis dari Lorne
@ user207421 Ini sebagian benar. Blok redirect adalah untuk protokol switch seperti http-> https yang tidak didukung secara default. Saya mencoba mengungkapkannya di komentar dalam kode. Lihat stackoverflow.com/questions/1884230/… .
jschnasse
-1

Berikut adalah contoh lengkap yang membaca konten halaman web yang diberikan. Halaman web dibaca dari bentuk HTML. Kami menggunakan InputStreamkelas standar , tetapi itu bisa dilakukan dengan lebih mudah dengan perpustakaan 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>  

Ini adalah dependensi Maven. Kami menggunakan perpustakaan Apache Commons untuk memvalidasi string 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));
    }
}

The ReadWebPageservlet membaca isi dari halaman web yang diberikan dan mengirimkannya kembali ke klien dalam format teks biasa. Tugas membaca halaman didelegasikan ke 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);
    }
}

WebPageReadermemvalidasi URL dan membaca konten halaman web. Ini mengembalikan string yang berisi kode HTML halaman.

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

Terakhir, ini adalah beranda yang berisi formulir HTML. Ini diambil dari tutorial saya tentang topik ini.

Jan Bodnar
sumber