InputStream từ một URL


117

Làm cách nào để lấy InputStream từ một URL?

ví dụ: tôi muốn lấy tệp tại url wwww.somewebsite.com/a.txtvà đọc nó dưới dạng InputStream trong Java, thông qua một servlet.

Tôi đã thử

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

nhưng những gì tôi nhận được là một lỗi:

java.io.FileNotFoundException

1
Tại sao bạn lại khôi phục việc xóa servletsthẻ? Không có javax.servlet.*API nào liên quan ở đây. Bạn sẽ gặp chính xác vấn đề tương tự khi làm như vậy trong một lớp Java vani thuần túy với một main()phương thức.
BalusC

1
Có lẽ bạn nên làm quen với những gì một URL là: docs.oracle.com/javase/tutorial/networking/urls/definition.html
b1nary.atr0phy

Câu trả lời:


228

Sử dụng java.net.URL#openStream()với một URL thích hợp (bao gồm cả giao thức!). Ví dụ

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

Xem thêm:


2
Bạn có biết liệu điều này có tạo ra một yêu cầu mạng trên mỗi lần đọc InputStream hay không hoặc liệu nó có đọc toàn bộ tệp cùng một lúc để nó không phải thực hiện các yêu cầu mạng khi đọc không?
gsingh2011

Gọi phương thức này trong chuỗi giao diện người dùng trong Android sẽ tạo ra một ngoại lệ. Làm điều đó trong một chủ đề nền. Sử dụng Bolts-Android
Behrouz.M


10

(a) wwww.somewebsite.com/a.txtkhông phải là 'URL tệp'. Nó không phải là một URL. Nếu bạn đặt http://ở mặt trước, nó sẽ là một URL HTTP, đây rõ ràng là những gì bạn dự định ở đây.

(b) FileInputStreamdành cho tệp, không phải URL.

(c) Cách lấy luồng đầu vào từ bất kỳ URL nào là thông qua URL.openStream(),hoặc đường URL.getConnection().getInputStream(),dẫn tương đương nhưng bạn có thể có những lý do khác để lấy URLConnectionvà sử dụng nó trước.


4

Mã gốc của bạn sử dụng FileInputStream để truy cập các tệp được lưu trữ trên hệ thống tệp.

Hàm tạo mà bạn đã sử dụng sẽ cố gắng định vị tệp có tên a.txt trong thư mục con www.somewebsite.com của thư mục làm việc hiện tại (giá trị của thuộc tính hệ thống user.dir). Tên bạn cung cấp được phân giải thành tệp bằng lớp Tệp.

Đối tượng URL là cách chung để giải quyết vấn đề này. Bạn có thể sử dụng URL để truy cập các tệp cục bộ cũng như các tài nguyên được lưu trữ trên mạng. Lớp URL hỗ trợ giao thức tệp: // bên cạnh http: // hoặc https: //, vì vậy bạn nên sử dụng.


2

Java thuần túy:

 urlToInputStream(url,httpHeaders);

Với một số thành công, tôi sử dụng phương pháp này. Nó xử lý các chuyển hướng và người ta có thể chuyển một số tiêu đề HTTP thay đổi như Map<String,String>. Nó cũng cho phép chuyển hướng từ HTTP sang 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);
    }
}

Cuộc gọi đầy đủ ví dụ

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

HttpURLConnectionsẽ thực hiện theo các chuyển hướng trừ khi bạn yêu cầu nó không làm như vậy, điều mà bạn chưa thực hiện.
Marquis of Lorne

1
Tôi biết OP không đề cập đến tiêu đề nhưng tôi đánh giá cao ví dụ ngắn gọn (tốt, coi đó là Java).
chbrown

@EJP Tôi đã thêm một số giải thích dưới dạng nhận xét nội tuyến. Tôi nghĩ, tôi chủ yếu giới thiệu khối chuyển hướng cho trường hợp HTTP 301 chuyển hướng địa chỉ HTTP đến địa chỉ HTTPS. Tất nhiên, điều này vượt ra ngoài câu hỏi ban đầu, nhưng là một trường hợp sử dụng phổ biến không được xử lý theo cách triển khai mặc định. Xem: stackoverflow.com/questions/1884230/…
jschnasse

Mã của bạn hoạt động tốt như nhau mà không có khối chuyển hướng, như HttpURLConnectionsau các chuyển hướng theo mặc định, như tôi đã nêu.
Marquis of Lorne

@ user207421 Điều này đúng một phần. Khối chuyển hướng dành cho các công tắc giao thức như http-> https không được hỗ trợ theo mặc định. Tôi đã cố gắng thể hiện điều đó trong nhận xét trong mã. Xem stackoverflow.com/questions/1884230/… .
jschnasse 14/12/18

-1

Đây là một ví dụ đầy đủ đọc nội dung của trang web nhất định. Trang web được đọc từ một biểu mẫu HTML. Chúng tôi sử dụng các InputStreamlớp tiêu chuẩn , nhưng nó có thể được thực hiện dễ dàng hơn với thư viện 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>  

Đây là những phụ thuộc Maven. Chúng tôi sử dụng thư viện Apache Commons để xác thực các chuỗi 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));
    }
}

Các ReadWebPageservlet đọc nội dung của các trang web nhất định và gửi nó lại cho khách hàng trong định dạng văn bản đơn giản. Nhiệm vụ đọc trang được giao cho 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);
    }
}

WebPageReaderxác thực URL và đọc nội dung của trang web. Nó trả về một chuỗi chứa mã HTML của trang.

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

Cuối cùng, đây là trang chủ chứa biểu mẫu HTML. Điều này được lấy từ hướng dẫn của tôi về chủ đề này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.