Search code examples
javafile-read

How do you detect if a file has a blank line at the end with a BufferedReader?


I am currently working on a INI file parsing library, but I just have one issue when I am attempting to create a category with a method that I made.

The content of the INI file that I am using is as followed:

; Format example
[Category]
key=value

; Just a test to see if setting the same key in a different category
; would mess up the reading, which it didn't.
[Language]
cplusplus=C++
key=java
(No extra line; file ends at "key=java")

When I am creating a category with the method, it will attempt to add enough new lines so each category has 1 blank line between the end of the previous category and the one you are creating. If I keep the file as is, which is with no extra blank line at the end of the file, it works fine. But if I change the file content to this:

; Format example
[Category]
key=value

; Just a test to see if setting the same key in a different category
; would mess up the reading, which it didn't.
[Language]
cplusplus=C++
key=java

(File has extra line; file ends after the "key=java" line)

It creates two empty lines between the two categories... But I don't understand why, as I check if the last line is already blank. I some-what new to Java, so please tell me if I am making some obvious mistake.

/**
 * Adds a category to the current INI file.
 * 
 * @param category The category to be added to the file
 */
public void addCategory(String category) {
    if (iniFile == null) return;

    // Checking to see if the file already contains the desired category
    boolean containsCategory = false;
    String lastLine = "";
    String string;

    try (BufferedReader in = new BufferedReader(new FileReader(iniFile))) {
        while ( (string = in.readLine()) != null) {
            // Line is a comment or is empty, ignoring
            if (!string.equals(""))
                if (string.charAt(0) == ';' || string.charAt(0) == '#')
                    continue;

            lastLine = string;

            // Line is a category, checking if it is the category that is
            // about to be created
            if (!string.equals("") && string.charAt(0) == '[') {
                String thisCategory = string.substring(1, string.length() - 1);
                if (thisCategory.equals(category))
                    containsCategory = true;
            }
        }
    } catch (IOException e) {}

    // The file does not contain the category, so appeanding it to the end
    // of the file.
    if (!containsCategory) {
        try (BufferedWriter out = new BufferedWriter(new FileWriter(iniFile, true))) {
            if (!lastLine.equals("")) {
                System.out.println("Adding extra whitespace");
                out.newLine();
                out.newLine();
            }

            out.write('[' + category + ']');
            out.close();
        } catch (IOException e) {}
    }
}

If you want to see the full file source, here is the link to the GitHub that it is uploaded on.

EDIT:

I just thought I should provide what the files look like after I call the addCategory(String) method.

After I call addCategory("Example") on the first file (No extra blank line):

; Format example
[Category]
key=value

; Just a test to see if setting the same key in a different category
; would mess up the reading, which it didn't.
[Language]
cplusplus=C++
key=java

[Example]

After I call addCategory("Example") on the second file (with an extra blank line at the end of the file):

; Format example
[Category]
key=value

; Just a test to see if setting the same key in a different category
; would mess up the reading, which it didn't.
[Language]
cplusplus=C++
key=java


[Example]

Solution

  • lastLine is going to be empty ("") if the last line in the file is nothing more than \n (or \r\n). readLine strips off the end-of-line character(s).

    You are only adding whitespace when writing the file if lastLine is not empty. So ... that's not the problem.

    However:

    1. You don't account for the last line possibly not having an end-of-line character.
    2. Your source file with the "extra" line ... doesn't have the end-of-line character(s) but has a space.

    That's the only thing that is going to generate the output you show. When you add two newlines you're adding one to the extra line that was missing it, then creating a second "blank" line; there weren't end-of-line characters.

    It's also why adding two newlines to the file that ends in key=java only produces one "blank line".

    You need to account for this when reading the file. A regex perhaps?

    In all honestly, it's simply easier to write the entire file each time. This is what the built in Properties object does in java.