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

如何使用Java套接字HTTP/1.1请求下载映像?,java,image,sockets,http,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); PrintWri

我正在尝试使用
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());
要查看流中的内容,请将
buffereImage
行交换为:

    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.buffereImage
javafx.scene.image.image
?后者有一个接受输入流的构造函数,我已经尝试过了,但它不起作用(因为http头?)。这个问题类似于一个问题,但我试图创建一个图像而不是一个文件。

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

  • 它将字节转换为
    字符串
    ,然后将其转换回字节以发送到输出流。转换可能(也可能)导致数据丢失
  • 它解析的字节太多,您无法控制它
  • 您需要通过外科手术来实现这一点,创建一个所需大小的字节缓冲区,并使用
    InputStream
    按自己的方式逐字节读取流。此外,由于您知道HTTP头的结尾是“\r\n\r\n”(或13 10字节),因此您可以扫描自己的缓冲区以查找此模式并相应地执行操作

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

    以下代码允许您通过剪切标题下载图像文件(或任何其他文件):
    //初始化流。
    最终文件输出流文件输出流=新文件输出流(文件);
    final InputStream InputStream=socket.getInputStream();
    //标题结束标志。
    布尔头指向=假;
    字节[]字节=新字节[2048];
    整数长度;
    而((长度=inputStream.read(字节))!=-1){
    //如果已经到达头的末尾,则按正常方式将字节写入文件。
    如果(有标题)
    fileOutputStream.write(字节,0,长度);
    //这将通过比较当前字节和接下来的3个字节来定位标头的结尾
    //HTTP头的结尾为“\r\n\r\n”(以整数表示为13 10)。
    //如果到达报头的末尾,则该标志将设置为true,并且报头中的剩余数据
    //当前缓冲的字节数组写入文件。
    否则{
    对于(int i=0;i<2045;i++){
    如果(字节[i]==13&&bytes[i+1]==10&&bytes[i+2]==13&&bytes[i+3]==10){
    headerEnded=正确;
    fileOutputStream.write(字节,i+42048-i-4);
    打破
    }
    }
    }
    }
    inputStream.close();
    fileOutputStream.close();
    
    您是否尝试过使用ImageInputStream而不是InputStream?为什么?为什么不使用
    HttpURLConnection
    ,省去很多麻烦呢?很麻烦。您将不得不处理内容长度、内容编码、HTTP 1.0、@Luis如何获得ImageInputStream?我尝试过对
    套接字进行类型转换。getInputStream
    但不起作用。@EJP我可以从套接字获得
    HttpURLConnection
    ?我想避免麻烦,但我正试图找出如何使用套接字和HTTP请求获取映像。(我的目标是学习)不,你不能那样做,你可以从URL获取。关于ImageInputStream的建议对您已经在做的事情没有多大帮助。此代码假定两个相邻的CRLF都以相同的读取方式到达。@EJP缓冲区大小可以根据需要增加。
        // 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();