Java BufferedReader - empty line issue

5.6k views Asked by At

Problem description: For example we have a text file file.txt with following content:

Hello(LS)
what(LS)
are(LS)
<empty_line>(LS)
you(LS)
doing(LS)
<empty_line>(LS)
<empty_line>(LS)
now(LS)
<empty_line>(LS)
<empty_line>(LS)
<empty_line>(EOF)

(LS - line separator, EOF - end of file)

If I understood the idea of text file, the file is looking something like that. Now, I want to fill up for example TextArea (from JavaFX) with this text. I can use the following code surrounded with try-catch (close() method would be in finnaly block):

TextArea textArea = new TextArea();
BufferedReader br = new BufferedReader(new FileReader(new File("file.txt")));
String line;
while ((line = br.readLine()) != null) {
       textArea.appendText(line);
       textArea.appendText("\n");
}

That code has one big problem - everytime there is one more line in the targeted TextArea when text file does't ending with empty_line. When file that empty_line contains before EOF, so loading into TextArea is working right. I tried a lot of way how to do it, but everytime there was some problems.

Why I chose BufferedReader? I chose BufferedReader because I just want some reader that can reads source text file line by line. I want that reader, because of file separator and OS independence.

What I expect from it? I am awaiting that I read file line by line and when I am reading I set up custom separators (independently for source file line separators) - for example LF ("\n"). And I am awaiting exactly the same content with possible different line separators! When I am writing to some file (where I am using BufferedReader too (for intern reading text from TextArea and set up line separators depended on user OS (System.getProperty("line.separator"))) there is a similar behavioral.

What I tried? I tried a lot of ways how to do it. I also tried use method read() in class BufferedReader and compare it's return value with -1, which is means EOF. BUT, there is one problem, I want to use custom file separators and I don't have all time to write some parsers.

My question: How can I write to TextArea (or any String) the file content with customed line separators without any extra or less line?

*As you can see, my english isn't very good, so I hope you understand me, thanks.

3

There are 3 answers

9
maraca On BEST ANSWER

As it turned out in the discussion, the problem is that with readLine() the following files will behave the same way:

File A: "Hello\n"
File B: "Hello"

1st readLine() --> "Hello"
2nd readLine() --> null

==> we cannot know if there was a '\n' after the last line or not

Solution: use other methods to read the characters, two of them explained here:

One character at a time:

String readFile(String file) throws IOException {
    FileReader fr = new FileReader(new File(file));
    String s = "";
    int c;
    while ((c = fr.read()) >= 0) {
        s += (c == '\n' ? myCharOrString : (char)c;
    }
    return s;
}

Buffered:

String readFile(String file, int bufferSize) throws IOException {
    FileReader fr = new FileReader(new File(file));
    char[] buffer = new char[bufferSize];
    int charsRead;
    String s = "";
    while ((charsRead = fr.read(buffer)) > 0) {
        s += new String(buffer, 0, charsRead);
    }
    return s.replaceAll("\\r\\n?", "\n");
}
1
Nik Novák On

Okey, I did it! I don't know how much is that effective or if I can use different Reader than BufferedReader, but this is working for me:

TextArea textArea = new TextArea();
String someString;
bufferedReader = new BufferedReader(new FileReader(file));

StringBuilder codeTextArea = new StringBuilder();
int character;
while ((character = bufferedReader.read()) != -1)
       codeTextArea.append((char) character);
//for TextArea you can use just toString and it set up separators to LF
this.textArea.setText(codeTextArea.toString());
//for String where you want line separator LF you can use for example following regex expression
someString = codeTextArea.toString().replaceAll("\r\n?","\n");

As you can see in the second case I am using regex expression for detecting and replace line separators. That code can read text files with separators LF, CR, CRLF and fill up it correctly (includes last empty line) in TextArea or String with the lowest memory requirement, because of one character ("\n") for line separate and also is corresponding with TextArea default line separator (it is using the same - LF).

That code probably isn't very simplify, but it works. So I am asking you if you know how to simplify it for best possible hardware performance.

5
alwaysAStudent On

You are adding the newline yourself.

while ((line = br.readLine()) != null) {
       textArea.appendText(line);
       textArea.appendText("\n");
}

The second line in while-loop adds the next line. Everytime that statement gets executed, the cursor will go to next line. So when the file cursor reads the last line from file, it appends it to the textArea and the then appends it with a new line character. Thats why you get extra blank line at the end.

if((line = br.readLine()) != null)
     textArea.appendText(line);
while ((line = br.readLine()) != null) {
       textArea.appendText("\n");
       textArea.appendText(line);
}