flexcookie flexcookie - 7 months ago 23
Java Question

Scanner missing first line of .txt file

I think I'm doing something really silly, but I'm new to Java so bear with me. I'm using a FileReader and Scanner to read through the lines of a .txt file. After grabbing each line, I extract some information out and then move the line. This is what my simplified method looks like:

Reader fileReader = new FileReader("test.txt");
Scanner scanner = new Scanner(fileReader);

public static textList(Scanner scanner){
while (scanner.hasNextLine()){
scanner.nextLine();
while(scanner.hasNext()){
// Extract information from each line and do some stuff with it
// using scanner.next();
}
}
}
// scanner is closed in the same method that creates it and the FileReader.


My problem is, if I leave the
scanner.nextLine()
where it is, I'll always skip the first line of the .txt file, but if I move it to the end of the
while( scanner.hasNextLine())
, I get a "no such line exists" exception when the scanner reaches the end of the .txt file.

Any help and guidance would be gratefully received!

Thanks

Answer

Best way to read a text file with 5 tokens per line, is to not use Scanner.

Scanner is slow, and often don't behave the way you think.

Use BufferedReader instead. And use try-with-resources to close it.

try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
    for (String line; (line = reader.readLine()) != null; ) {
        String[] tokens = line.split("\\s+");
        // use tokens array here
    }
}

For more advanced line parsing, you can use a full regular expression with capture groups, instead of split().

Pattern p = Pattern.compile("(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)");
try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
    for (String line; (line = reader.readLine()) != null; ) {
        Matcher m = p.matcher(line);
        if (! m.matches())
            throw new IllegalArgumentException("Bad data: " + line);
        String token1 = m.group(1);
        String token2 = m.group(2);
        String token3 = m.group(3);
        String token4 = m.group(4);
        String token5 = m.group(5);
        // use tokens here
    }
}

That code does the same as the first example, but enforces that every line must have exactly 5 tokens. The regular expression can then be adjusted as needed, e.g. to ensure that token3 is a number by using \\d+ instead of \\S+.

Comments