Search code examples
javafilesocketstransfer

Does Java´s BufferedReader leaves bytes in its internal buffer after a readline() call?


I´m having a problem, in my server, after I send a file with X bytes, I send a string saying this file is over and another file is coming, like

FILE: a SIZE: Y\r\n
send Y bytes
FILE a FINISHED\r\n
FILE b SIZE: Z\r\n
send Z byes
FILE b FINISHED\r\n
FILES FINISHED\r\n

In my client it does not recive properly. I use readline() to get the command lines after reading Y or Z bytes from the socket. With one file it works fine, with multiple files it rarely works (yeah, I dont know how it worked once or twice)

Here are some code I use to transfer binary

public static void readInputStreamToFile(InputStream is, FileOutputStream fout,
        long size, int bufferSize) throws Exception
{
    byte[] buffer = new byte[bufferSize];
    long curRead = 0;
    long totalRead = 0;
    long sizeToRead = size;
    while(totalRead < sizeToRead)
    {
        if(totalRead + buffer.length <= sizeToRead)
        {
            curRead = is.read(buffer);
        }
        else
        {
            curRead = is.read(buffer, 0, (int)(sizeToRead - totalRead));
        }
        totalRead = totalRead + curRead;
        fout.write(buffer, 0, (int) curRead);
    }
}





public static void writeFileInputStreamToOutputStream(FileInputStream in, OutputStream out, int bufferSize) throws Exception
{
    byte[] buffer = new byte[bufferSize];
    int count = 0;
    while((count = in.read(buffer)) != -1)
    {
        out.write(buffer, 0, count);
    }
}

just for note I could solve replacing readline to this code:

    ByteArrayOutputStream ba = new ByteArrayOutputStream();
    int ch;
    while(true)
    {
        ch = is.read();
        if(ch == -1)
            throw new IOException("Conecção finalizada");
        if(ch == 13)
        {
            ch = is.read();
            if(ch == 10)
                return new String(ba.toByteArray(), "ISO-8859-1");
            else
                ba.write(13);
        }
        ba.write(ch);
    }

PS: "is" is my input stream from socket: socket.getInputStream();

still I dont know if its the best implementation to do, im tryinf to figure out


Solution

  • There's no readLine() calls in the code here, but to answer your question; Yes, calling BufferedReader.readLine() might very well leave stuff around in its internal buffer. It's buffering the input.

    If you wrap one of your InputStream in a BufferedReader, you can't really get much sane behavior if you read from the BufferedReader and then later on read from the InputStream.

    You could read bytes from your InputStream and parse out a text line from that by looking for a pair of \r\n bytes. When you got a line saying "FILE: a SIZE: Y\r\n" , you go on as usual, except the buffer you used to parse lines might contain the first few bytes of your file, so write those bytes out first.

    Or you use the idea of FTP and use one TCP stream for commands and one TCP stream for the actual transfer, reading from the command stream with a BufferedReader.readLine(), and reading the data as you already do with an InputStream.