如何使用Java套接字HTTP / 1.1请求下载图像?

时间:2015-11-06 22:10:31

标签: java image sockets http

我正在尝试使用java.net.Socket而不使用java.net.URL和外部库来下载图像。这就是我所拥有的,我不确定什么是无效的。

        String domain = "www.manchester.edu";
        String path = "/images/default-source/default-album/slide1.jpg";
        Socket socket = new Socket(domain,80);

        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
        out.println("" +
                "Get "+path+" HTTP/1.1\n" +
                "Host: "+domain+"\n"+
                "");
        out.println();
        out.flush();

        BufferedImage image = ImageIO.read(socket.getInputStream());

要查看流中的内容,请将BufferedImage行换成:

    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String inputLine;
    while ((inputLine = in.readLine()) != null && inputLine.trim() != "0") {
       System.out.println(inputLine);
    }

假设ImageIO.read(...)方法不期望套接字输入流中的HTTP标头。但我不知道如何删除标题。我尝试使用BufferedReader读取标题行,然后将套接字输入流传递给ImageIO.read(...),但这不起作用。

以下是BufferedReader打印的字符串:

HTTP/1.1 200 OK
Cache-Control: public, max-age=7776000
Content-Length: 96876
Content-Type: image/jpeg
Expires: Thu, 04 Feb 2016 21:36:46 GMT
Last-Modified: Tue, 15 Sep 2015 14:23:40 GMT
Server: Microsoft-IIS/8.5
content-disposition: inline; filename=slide1.jpg
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 06 Nov 2015 21:36:46 GMT

����...

最后的不可打印字符似乎表明标题后面的内容是某种形式的图像。但是,如何将其转换为java.awt.image.BufferedImagejavafx.scene.image.Image?后者有一个构造函数,它接受输入流,我已经尝试过,但它不起作用(因为http头?)。这个问题与this类似,但我试图创建一个图像而不是文件。

1 个答案:

答案 0 :(得分:2)

使用BufferedReader是一个错误,有两个原因:

  1. 它将字节转换为String,然后将其转换回字节以将其发送到输出流。转换可能(并且可能会)导致数据丢失;
  2. 它解析了太多字节而你无法控制它。
  3. 你需要手术接近,创建一个所需大小的字节缓冲区,并使用InputStream按照你自己的条件逐字节读取流。此外,因为您知道HTTP标头结尾是" \ r \ n \ r \ n" (或13 10 13 10字节),您可以扫描自己的缓冲区以获得此模式,并采取相应的行动。

    最好的办法是将图像下载到文件中,然后使用ImageIO从本地文件中读取图像。

    这里的代码允许您通过剪切标题来下载图像文件(或任何其他文件):

        // Initialize the streams.
        final FileOutputStream fileOutputStream = new FileOutputStream(file);
        final InputStream inputStream = socket.getInputStream();
    
        // Header end flag.
        boolean headerEnded = false;
    
        byte[] bytes = new byte[2048];
        int length;
        while ((length = inputStream.read(bytes)) != -1) {
            // If the end of the header had already been reached, write the bytes to the file as normal.
            if (headerEnded)
                fileOutputStream.write(bytes, 0, length);
    
            // This locates the end of the header by comparing the current byte as well as the next 3 bytes
            // with the HTTP header end "\r\n\r\n" (which in integer representation would be 13 10 13 10).
            // If the end of the header is reached, the flag is set to true and the remaining data in the
            // currently buffered byte array is written into the file.
            else {
                for (int i = 0; i < 2045; i++) {
                    if (bytes[i] == 13 && bytes[i + 1] == 10 && bytes[i + 2] == 13 && bytes[i + 3] == 10) {
                        headerEnded = true;
                        fileOutputStream.write(bytes, i+4 , 2048-i-4);
                        break;
                    }
                }
            }
        }
        inputStream.close();
        fileOutputStream.close();