InputStream จาก URL


117

ฉันจะรับ InputStream จาก URL ได้อย่างไร

ตัวอย่างเช่นฉันต้องการรับไฟล์ที่ url wwww.somewebsite.com/a.txtและอ่านเป็น InputStream ใน Java ผ่าน servlet

ฉันพยายามแล้ว

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

แต่สิ่งที่ฉันได้รับคือข้อผิดพลาด:

java.io.FileNotFoundException

1
เหตุใดคุณจึงย้อนกลับการลบservletsแท็ก ที่นี่ไม่มีjavax.servlet.*API ที่เกี่ยวข้อง คุณจะมีปัญหาเดียวกันmain()ทุกประการเมื่อทำเช่นนั้นในคลาสวานิลลา Java ธรรมดาด้วยวิธีการ
BalusC

1
บางทีคุณควรทำความคุ้นเคยว่า URL คืออะไร: docs.oracle.com/javase/tutorial/networking/urls/definition.html
b1nary.atr0phy

คำตอบ:


228

ใช้java.net.URL#openStream()กับ URL ที่เหมาะสม (รวมถึงโปรโตคอล!) เช่น

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

ดูสิ่งนี้ด้วย:


2
คุณรู้หรือไม่ว่าสิ่งนี้ทำให้การร้องขอเครือข่ายในการอ่าน InputStream แต่ละครั้งหรือการอ่านทั้งไฟล์พร้อมกันจึงไม่ต้องทำการร้องขอเครือข่ายในการอ่าน
gsingh2011

การเรียกใช้เมธอดนี้ในเธรด UI ใน Android จะทำให้เกิดข้อยกเว้น ทำในเธรดพื้นหลัง ใช้Bolts-Android
Behrouz.M


10

(a) wwww.somewebsite.com/a.txtไม่ใช่ "URL ของไฟล์" ไม่ใช่ URL เลย ถ้าคุณวางไว้http://ด้านหน้ามันจะเป็น HTTP URL ซึ่งเป็นสิ่งที่คุณตั้งใจไว้ที่นี่อย่างชัดเจน

(b) ใช้FileInputStreamสำหรับไฟล์ไม่ใช่ URL

(c) วิธีรับสตรีมอินพุตจากURL ใด ๆคือผ่านURL.openStream(),หรือURL.getConnection().getInputStream(),เทียบเท่า แต่คุณอาจมีเหตุผลอื่นในการรับURLConnectionและเล่นกับมันก่อน


4

รหัสเดิมของคุณใช้ FileInputStream ซึ่งใช้สำหรับการเข้าถึงไฟล์ที่โฮสต์ระบบไฟล์

ตัวสร้างที่คุณใช้จะพยายามค้นหาไฟล์ชื่อ a.txt ในโฟลเดอร์ย่อย www.somewebsite.com ของไดเร็กทอรีการทำงานปัจจุบัน (ค่าของคุณสมบัติระบบ user.dir) ชื่อที่คุณระบุได้รับการแก้ไขเป็นไฟล์โดยใช้คลาส File

ออบเจ็กต์ URL เป็นวิธีทั่วไปในการแก้ปัญหานี้ คุณสามารถใช้ URL เพื่อเข้าถึงไฟล์ในเครื่อง แต่ยังรวมถึงทรัพยากรที่โฮสต์บนเครือข่ายด้วย คลาส URL รองรับไฟล์: // protocol นอกเหนือจาก http: // หรือ https: // ดังนั้นคุณจึงพร้อมใช้งาน


2

Java บริสุทธิ์:

 urlToInputStream(url,httpHeaders);

ด้วยความสำเร็จฉันใช้วิธีนี้ มันจัดการเปลี่ยนเส้นทางและหนึ่งสามารถผ่านจำนวนตัวแปรของส่วนหัว HTTPMap<String,String>เป็น นอกจากนี้ยังช่วยให้การเปลี่ยนเส้นทางจาก HTTP เพื่อ 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);
    }
}

ตัวอย่างการโทร

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

HttpURLConnectionจะติดตามการเปลี่ยนเส้นทางอยู่แล้วเว้นแต่คุณจะบอกว่าไม่ทำซึ่งคุณไม่ได้ทำ
Marquis of Lorne

1
ฉันรู้ว่า OP ไม่ได้พูดถึงส่วนหัว แต่ฉันขอขอบคุณตัวอย่างที่รวบรัด (โดยพิจารณาว่าเป็น Java)
chbrown

@EJP ฉันเพิ่มคำอธิบายเป็นความคิดเห็นแบบอินไลน์ ฉันคิดว่าฉันแนะนำบล็อกการเปลี่ยนเส้นทางเป็นหลักในกรณีที่ HTTP 301 เปลี่ยนเส้นทางที่อยู่ HTTP ไปยังที่อยู่ HTTPS แน่นอนว่าสิ่งนี้เกินกว่าคำถามเดิม แต่เป็นกรณีการใช้งานทั่วไปที่ไม่ได้รับการจัดการโดยการใช้งานเริ่มต้น ดู: stackoverflow.com/questions/1884230/…
jschnasse

รหัสของคุณทำงานได้ดีพอ ๆ กันโดยไม่มีการบล็อกการเปลี่ยนเส้นทางตามที่HttpURLConnectionมีการเปลี่ยนเส้นทางตามค่าเริ่มต้นแล้วตามที่ฉันได้ระบุไว้แล้ว
Marquis of Lorne

@ user207421 นี้ถูกต้องบางส่วน บล็อกการเปลี่ยนเส้นทางมีไว้สำหรับสวิตช์โปรโตคอลเช่น http-> https ซึ่งไม่รองรับโดยค่าเริ่มต้น ฉันพยายามแสดงสิ่งนั้นในความคิดเห็นในรหัส ดูstackoverflow.com/questions/1884230/...
jschnasse

-1

นี่คือตัวอย่างทั้งหมดที่อ่านเนื้อหาของหน้าเว็บที่ระบุ หน้าเว็บอ่านจากรูปแบบ HTML เราใช้InputStreamคลาสมาตรฐานแต่สามารถทำได้ง่ายกว่าด้วยไลบรารี 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>  

สิ่งเหล่านี้คือการพึ่งพา Maven เราใช้ไลบรารี Apache Commons เพื่อตรวจสอบสตริง 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));
    }
}

ReadWebPageเซิร์ฟเล็ตอ่านเนื้อหาของหน้าเว็บที่ได้รับและส่งกลับไปยังลูกค้าในรูปแบบข้อความธรรมดา 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ตรวจสอบความถูกต้องของ URL และอ่านเนื้อหาของเว็บเพจ ส่งคืนสตริงที่มีโค้ด HTML ของเพจ

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

สุดท้ายนี่คือโฮมเพจที่มีรูปแบบ HTML นำมาจากบทแนะนำของฉันเกี่ยวกับหัวข้อนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.