Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read a line of text from an input stream in Java keeping the line-termination character(s)

I have this code in Java:

InputStreamReader isr = new InputStreamReader(getInputStream());
BufferedReader ir = new BufferedReader(isr);
String line;
while ((line = ir.readLine()) != null) {
 //do stuff with "line"
}

If the input stream contains the following: "hello\nhey\ryo\r\ngood-day", then line variable would be following on each iteration:

  1. hello
  2. hey
  3. yo
  4. good-day

I want to read one line at a time, but I want to keep the line-termination character(s):

  1. hello\n
  2. hey\r
  3. yo\r\n
  4. good-day

How can I do this? Is there a ready-made classes I can use?

--

Update:

Here's what I'm trying to do and why I need to keep the end-of-line character (and why the EOL character may be different).

I'm reading a POST request. They consists of pure text messages where the lines always end with \r\n (by the standard specification). However POST request may contain binary data, which may contain bytes that look like termination characters to Java Reader objects.

In my example, an image is being uploaded. The image data is sent on a single line. However, however the image's binary data contains bytes that the READER would interpret as "\n", "\r" or sometimes "\r\n" if those two bytes happens to be next to each other.

I have to read the POST request one line at a time because that's how it works. I suppose, I COULD read everything and then parse the whole thing. But that's not efficient, especially if a large file (say 1024 MiB) file is being uploaded.

like image 305
Mike Avatar asked Dec 15 '10 00:12

Mike


1 Answers

If you want to read a HTTP POST request, I strongly suggest using BufferedInputStream.read() (not BufferedReader!) directly (without readLine-like intermediate abstractions), paying attention to all details manually, including the handling of CR and LF according to the HTTP RFC.

Here is my answer to your more specific question (how to implement exactly that readLine). This might not be the fastest solution, but it's time complexity is optimal, and it works:

import java.io.BufferedReader;
import java.io.IOException;   
public class LineReader {   
  private int i = -2;
  private BufferedReader br;
  public OriginalLineReader(BufferedReader br) { this.br = br; }
  public String readLine() throws IOException {
    if (i == -2) i = br.read();
    if (i < 0) return null;
    StringBuilder sb = new StringBuilder();
    sb.append((char)i);
    if (i != '\r' && i != '\n') {
      while (0 <= (i = br.read()) && i != '\r' && i != '\n') {
        sb.append((char)i);
      }
      if (i < 0) return sb.toString();
      sb.append((char)i);
    }
    if (i == '\r') {
      i = br.read();
      if (i != '\n') return sb.toString(); 
      sb.append((char)'\n');
    }
    i = -2;
    return sb.toString();
  }
}

You won't find such a readLine built into Java. It's likely that you will find similar, but not exactly matching readLines in a third-party .jar file. My recommendation is just to use the one above, if you really need that feature.

like image 136
pts Avatar answered Nov 15 '22 19:11

pts