简体   繁体   中英

How to download an image using Java Socket from a remote Http server?

I have been trying to implement a simple http client using Java Socket. In my program I am requesting an Image from a server and trying to copy the requested JPEG image on local machine. I have managed to construct the request and received the desired content. I have also separated the response header and the content. But the problem is when I write the bytes using FileOutputStream into a .jpeg file and after writing when open the file in a image viewer (like picasa) the image seems to be invalid. Here is my entire code. Can anyone plz tell me what's wrong with code? Why the image is invalid?

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import sun.misc.IOUtils;


public class ImageCopy {
   public static void main(String args[]) throws IOException{
               String host = "www.uni-koblenz-landau.de";   //declare the host name
               String resourceLoc = "/images/starts-c-ko.jpg"; //declare the specific pagename of get
               HttpRequester req = new HttpRequester();
               req.request(host, resourceLoc); //send the request mentiong the host and pagename


   }
  }

class HttpRequester{
    public void request(String host, String resourceLoc) throws IOException{
         Socket httpSocket = new Socket(host, 80); //create the request for port 80
         PrintWriter writer = new PrintWriter(httpSocket.getOutputStream());
         FileOutputStream foutStream = new FileOutputStream("E:\\quora.jpeg"); //creating file to hold the output stream

         // building the header fields
        String protocol = "GET /" +resourceLoc+" HTTP/1.1";
        String connection ="Connection: close";
        String acceptedLanguage ="Accept-Language: de,en;q=0.7,en-us;q=0.3";
        String headerEnd = "";
        String HostHeader = "Host: www.uni-koblenz-landau.de";

        // writing the headers to the outputstream

       writer.println(protocol);
       writer.println(HostHeader);
       writer.println(connection);
       writer.println(acceptedLanguage);
       writer.println(headerEnd);

       writer.flush();

      // request sent

       BufferedInputStream reader = new BufferedInputStream(httpSocket.getInputStream());

       InputStream is;

       int byteCode =0;
       char ch ;
           StringBuilder builder = new StringBuilder();

       while((byteCode=reader.read())!=-1)
       {
           builder.append((char)byteCode);
          // System.out.print((char)byteCode);

       }

       String text = builder.toString();
       // sub[0] is supposed to contain the header and sub[1] should contain the bytes of the           image

       String[] sub = text.split("\r\n\r\n");
       System.out.println(sub[0]);

       byte[] byts = sub[1].getBytes();

       for(int i=0;i<byts.length;i++){
           foutStream.write(byteCode);
       }
       System.out.println(byts.length);
    }

}  

Please try this working code first:

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class URLTest {

  private static void sendGet() throws Exception {

    String url = "http://www.uni-koblenz-landau.de/images/starts-c-ko.jpg";

    URL obj = new URL(url);
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();

    // optional default is GET
    con.setRequestMethod("GET");

    //add request header
    con.setRequestProperty("User-Agent", "Mozilla/5.0");

    int responseCode = con.getResponseCode();
    System.out.println("\nSending 'GET' request to URL : " + url);
    System.out.println("Response Code : " + responseCode);

    InputStream in = con.getInputStream();
    OutputStream out = new FileOutputStream("/Users/ravikiran/Desktop/abc.jpg");
    try {
      byte[] bytes = new byte[2048];
      int length;

      while ((length = in.read(bytes)) != -1) {
        out.write(bytes, 0, length);
      }
    } finally {
      in.close();
      out.close();
    }
  }

  public static void main(String[] args) throws Exception {
    sendGet();
  }
}

There are at least 2 problems in shown code. First is trivial, near the end of program you have :

   byte[] byts = sub[1].getBytes();

   for(int i=0;i<byts.length;i++){
       foutStream.write(byteCode);
   }

I think foutStream.write(byts[i]); should be better.

The second is more subtle. You get bytes, convert them as char in a string builder and then get them back as bytes. That does not work as expected for byte values >= 128.

I just did this little test :

public class ByteCharTest {
    @Test
    public void test1() {
        byte[] bytes = new byte[]{ 'x', (byte) 0xc3, (byte) 0xa9,
            (byte) 0xc3, (byte) 0xa8, 'y', (byte) 0xe9, (byte) 0xe8, 'z'};
        StringBuilder sb = new StringBuilder();
        for(byte b: bytes) {
            sb.append((char) b);
        }
        String s = sb.toString();
        byte[] byte2 = s.getBytes();
        assertEquals(bytes.length, byte2.length);
        for(int i=0; i<bytes.length; i++) {
            assertEquals(bytes[i], byte2[i]);
        }
    }
}

And it breaks. Under debugger, string s is "x\ᅫ\ᄅ\ᅢ\ᄅy\←\│z" because the conversion from byte to char propagated sign bit and byte2 is x????y??z

The test works if the StringBuilder is fed with :

            sb.append((char) (((int) b) && 0xff));

So in your code, you should have :

   while((byteCode=reader.read())!=-1)
   {
       builder.append((char) (((int) byteCode) && 0xff));
      // System.out.print((char)byteCode);
   }

Just to explain the tested bytes, 0xc3 0xa9 and 0xc3 0xa8 are UTF-8 codes for éè and 0xe8 0xe9 are Latin1 codes for éè ...

The solution that actually fits your question:

// Initialize the stream.
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)
        foutStream.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;
                foutputStream.write(bytes, i+4, 2048-i-4);
                break;
            }
        }
    }
}
inputStream.close();
foutStream.close();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM