Java. Reading from BufferedInputStream and write to FileOutputStream

13.3k views Asked by At

I'm trying to write client and server side on java. Server side is ok (checked on several clients).

So, the problem is on client side. I allocate memory for bytearray, read from BufferedInputStream and write to that bytearray. Then writing from bytearray to FileOutputStream. Everything is ok but free space of bytearray is filling by NULLs, so received file is not correct(e.g. images).

I found 2 decision of that problem:

  1. Read to bytearray till the end of file(but I don't know where the end of file)
  2. Read from BufferedInputStream to FileInputStream, but it doesn't work:

I actually need receive header and file. Output header to console and write the file to the disc.

Full Source

public class SClient {
private static int bufferSize = 8192;
/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    System.out.println("Enter the address:");
    BufferedReader bufferRead = new BufferedReader
                (new InputStreamReader(System.in));

    try {
        String address = bufferRead.readLine();
        System.out.println("Enter the extention of receiving file:");
        String fileExt = bufferRead.readLine();
        // TODO code application logic here
        Socket socket = new Socket(address,4040);
        BufferedInputStream bis = new BufferedInputStream
                (socket.getInputStream());

        BufferedOutputStream bout = new BufferedOutputStream
                (socket.getOutputStream());
        System.out.println("Enter the request:");
        String message = bufferRead.readLine();// GET /index.html HTTP/1.0

        System.out.println("Header read");
        if(message!=null){
            bout.write(message.getBytes());
        }
        FileOutputStream fout = new FileOutputStream("out"+fileExt);
        String s1 = "\r\n\r\n";
        bout.write(s1.getBytes());
        bout.flush();
        System.out.println("Header sent");

        byte[] res = new byte[bufferSize];
        int got;
        while((got = bis.read(res))!=-1){
            fout.write(res,0,got);
        }
        fout.close();
        bout.flush();
        socket.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}

Server side source:

    String endLine = "\r\n";
    File f = new File(fileName);
    FileInputStream fstream;
    fstream = new FileInputStream(f);
    response = "HTTP/1.0 200 OK" + endLine;
    header = "Content-type: "+ contentType + endLine + "Content-length: " + f.length() + endLine + endLine;
    bout.write(response.getBytes());
    bout.write(header.getBytes());
    while(fstream.read(buffer) != -1) {
        bout.write(buffer);
    }
    System.out.println("Message sent");
    bout.flush();
    socket.close();
3

There are 3 answers

19
Matthias On BEST ANSWER

You have to remember the amount of bytes you read into your buffer and must only write those bytes back. Like this here:

int got;
while ((got = bis.read(res)) != -1) {

    fout.write(res, 0, got);
}
0
user207421 On

Memorize the canonical way to copy streams in Java:

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

Use any buffer size greater than zero, typically 4k or 8k.

3
MadProgrammer On

Not the answer, but a suggestion...

This doesn't look right. Basically, you are reading a an array of bytes up to a maximum of bufferSize, but then just writing a single byte to the output stream. You are also risking an index out of bounds error because you are incrementing the i on each loop unbound...

while (bis.read(res) != -1) {
    fout.write(res[i]);
    i++;
}

Instead you should be using something more like...

int bytesRead = -1;
while ((bytesRead = bis.read(res)) != -1) {
    fout.write(res, 0, bytesRead);
}

Which will write a the byte array up to the number of bytes read...

The next problem is, you need some way to know when the you've reached the end of the file.

Now, you can put in some kind of terminator character but that could, potentially, corrupt the output file.

Now, because I'm a UI developer, I like to know how much I'm downloading. So, the first then you could send down the stream is the number of bytes to expect, then you can simply keep a count of the bytes read and stop when you've reached your limit...

This would require a slight change to your server, it would need to be able to send a long value, indicating the size of the image (in bytes) to be read and a \n

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String header = br.readLine();
long expectedBytes = Long.parseLong(header);

Then you would simply loop until you have the required number of bytes...

int bytesRead = 0;
int totalBytes = 0;
while (totalBytes < expectedBytes) {
    bytesRead = bis.read(res);
    fout.write(res, 0, bytesRead);
    totalBytes += expectedBytes;
}

// Flush and close your steams as required.

I did something simular for a screen sharing question