mag_zbc
mag_zbc

Reputation: 6992

BufferedReader - read all characters (not lines)

How to read all available characters to a String using BufferedReader?

I have a Socket from which I want to read data, when available, and store it in a String. The thing is, I can't use readLine because the data I receive not always contains a newline or caret return, and readLine blocks thread until it can read a full line. How to use read instead?

thread = new Thread(() ->
    {
        try {
            out = new PrintWriter(client.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));

             while(true) 
             {
                if (in.ready())
                {
                    String someString = // ? read available data
                    delegate.didReadData(this, someString);
                }
             }

        } catch (IOException e) {
            delegate.didDropSocket(this);
        }
    });
    thread.start();

edit
1. delegate doesn't care how long the string is, it just needs to handle any hada that arrives via socket - and full contents of it
2. I don't need to cut data into chunks - I want to read everyhing that arrives
3. Yes, I have an infinite loop for I need to stay connected to the socket and listen for data until client drops the connection - when I get an IOException. I use a separate thread for socket because there will be much more sockets to listen to.

Upvotes: 0

Views: 3276

Answers (2)

Kayaman
Kayaman

Reputation: 73578

You need to always explicitly specify which encoding you're using, you don't need to check before reading, and of course you have to keep track of how much you've read and whether the other end has closed the connection.

Exception handling and closing of resources is omitted. Buffer size can be increased if necessary. Otherwise this is a pretty idiomatic read-loop.

out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
char[] buf = new char[4096];
int size = 0;
while((size = in.read(buf)) != -1) {
    String someString = new String(buf, 0, size);
    delegate.didReadData(this, someString);
}

Upvotes: 2

Max Barraclough
Max Barraclough

Reputation: 264

BufferedReader#readLine(0) treats '\n', '\r', and "\r\n" as line-separators. This behaviour cannot be changed, so as you say, we need to use one of the two overloads of read instead.

What does delegate need? Does it care how long someString is? Do you need to 'chunk' the data you read from in? Are you sure that String is appropriate?

I suspect that you want the read(char[] cbuf, int off, int len) method.

Assuming you don't need to read one char at a time, you'll get better performance using that chunk-at-a-time overload of read, than using the one-char-at-a-time overload.

Also, you have an infinite loop. Even when ready returns false, your code won't terminate, as you never leave your while(true) loop.

Or is the intent here to have the thread constantly check for more data, without end? I'm not familiar enough with the Java standard library to give details, but I'm confident there's a better way to do it than to have a thread run one of your cores at 100% load, checking for additional data. The simple hack would be to add a sleep call, but I'm sure there's a better way, perhaps involving the Stream class.

Upvotes: 1

Related Questions