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.