Ri Di
Ri Di

Reputation: 163

BufferedReader's read() too slow, readLine() returns no NL or CR

I am reading bytes coming through TCP with BufferedReader. Problem is readLine() reads until byte 10 or 10 and 13. It does not return those NL and CR. I need all bytes (because they all are data). With just NL it is ok, I can add '\n' after every readLine(), but problem is I dont know if there is carriage return after NL, which would also be removed by readLine(), so I wouldnt know if to add it too. read() solves this problem but it is very, very, very slow. Unusable. Is there a way to use something else? Because the only way to do that is to edit data coming through server to fit this stupid readLine() algorithm...

Upvotes: 0

Views: 1030

Answers (4)

Joni
Joni

Reputation: 111259

Never ever use string concatenation with + to construct the response when reading from a file. Since String is immutable, using + has to create a new string every time, just to add a single character.

Never use the int read() method or any other method that reads or writes single characters at a time. The added overhead per character does not go away completely, not even when you use a stream that incorporates a buffer like BufferedReader.

What you should do is use a buffer of a non-trivial size (1-2k is typically enough) when you read, and construct strings using the StringBuilder class. Like this:

mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));

char[] buffer = new char[1500];
int read;
StringBuilder strBuilder = new StringBuilder();
while ((read = mBufferIn.read(buffer)) > -1) {
    strBuilder.append(buffer, 0, read);
}
mServerMessage = strBuilder.toString();

Upvotes: 0

Stephen C
Stephen C

Reputation: 718856

If your read rate is ~70kb per minute, then the problem is in your operating system or network connection or the server you are reading from.

Rewriting the client-side code won't fix this problem.

Upvotes: 1

Alex Voss
Alex Voss

Reputation: 176

It looks like you are trying to read binary data rather than textual data, so readLine() is not appropriate. As Henry points out in their comment, readLine() uses one of the read methods, so cannot possibly be faster that all of them. Try one of the read operations that takes a buffer (byte[]) as an argument.

If that does not solve it, consider whether it could be the speed of the server or if the speed is rate-limited not by the call to read() but by what happens once the data have been read. If you are reading only at the speed at which your code can process then the later stages of your processing pipeline may be the issue.

It might help to see some of the code and learn more about the source of the images and what happens to them after they are read.

Upvotes: 0

rzwitserloot
rzwitserloot

Reputation: 102978

On modern java this is a solved problem but android has ancient libraries... but I think guava is usable (and possibly, included by default already?) - try this:

InputStream in = socket.getInputStream();
String data;
try {
    InputStreamReader reader = new InputStreamReader(in, "UTF-8");
    // you're going to have to figure out what the encoding is
    // - usually it's either UTF-8 or ISO-8859-1.
    // if you don't specify it, you get platform default. You don't want that.

    data = com.google.common.io.CharStreams.toString(reader);

} finally {
    in.close();
}

System.out.println(data);

The trick is not to call read(), but to call read(char[]) - but this is a method that is a bit tricky to use (it guarantees that it won't return until end of stream is reached or at least 1 character is read; it does not fill up the char array necessarily. The CharStreams.toString method will read as fast as possible and read it all.

If the above code still results in a 70kb/s transfer rate, well, then that's what it is. The phone's connection is slow or the server is slow, or something in between. Given that you're currently using BufferedReader, I'm pretty sure this is indeed the case (The whole point of BufferedReader is that its read() method is decently fast, vs. raw streams where that tends to be very slow).

NB: It is possible you don't want a string at all here, but bytes instead. Same principle:

InputStream in = socket.getInputStream();
byte[] data;
try {
    // now no need to worry about encoding!

    data = com.google.common.io.ByteStreams.toByteArray(in);
} finally {
    in.close();
}

Upvotes: 0

Related Questions