0

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

flexcookie
  • 113
  • 1
  • 2
  • 11
  • 2
    Why not use - `while (scanner.hasNextLine()){ String s = scanner.nextLine() ... Other code here`? – TheLostMind Apr 29 '16 at 05:37
  • Is it possible to then extract the different tokens from s? I'll clarify, each line has 5 strings of data on it, I need to separate those data bits – flexcookie Apr 29 '16 at 05:39
  • 1
    `nextLine()` consumes and returns a line of text. `next()` skips whitespace, the consumes and returns one token. So, any text consumed by your call to `nextLine()` is discarded, because you don't use the return value. – Andreas Apr 29 '16 at 05:40
  • @flexcookie - Yes, you can split the input line on whitespaces to get tokens – TheLostMind Apr 29 '16 at 05:40
  • Yes. `s = scanner.nextLine()` will assign the content of the next line to `s`, since `nextLine()` returns a String. – Bethany Louise Apr 29 '16 at 05:41

2 Answers2

1

An easy way to get around this issue would be doing it the way it is done in this answer - that way you'd get around even multiple whitespaces quite nicely:

String data = scanner.nextLine();
String[] pieces = data.split("\\s+");
// Parse the pieces

as .next() by default just returns what comes after a space, there's no benefit in using that instead of this here.

Community
  • 1
  • 1
eis
  • 45,245
  • 11
  • 129
  • 177
1

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+.

Andreas
  • 138,167
  • 8
  • 112
  • 195