dc4teg
dc4teg

Reputation: 109

Java parse .txt file

I am trying to run the below file TemplateMaker.java in Netbeans IDE 8.0.2 and am running into the following error message. Netbeans shows no red indicators for me to fix. Please help.

Exception in thread "main" java.util.NoSuchElementException
    at java.util.Scanner.throwFor(Scanner.java:907)
    at java.util.Scanner.next(Scanner.java:1416)
    at templatemaker.TemplateMaker.processLine(TemplateMaker.java:48)
    at templatemaker.TemplateMaker.processLineByLine(TemplateMaker.java:35)
    at templatemaker.TemplateMaker.main(TemplateMaker.java:17)
Java Result: 1

Here is my source code:

package templatemaker;


import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;


public class TemplateMaker {

        public static void main(String [] args)
 throws IOException {
    TemplateMaker parser = new TemplateMaker("Book1.txt");
    parser.processLineByLine();
    log("Done.");
  }

  /**
   Constructor.
   @param aFileName full name of an existing, readable file.
  */
  public TemplateMaker(String aFileName){
    fFilePath = Paths.get(aFileName);
  }


  /** Template method that calls {@link #processLine(String)}.
     * @throws java.io.IOException */
  public final void processLineByLine() throws IOException {
    try (Scanner scanner =  new Scanner(fFilePath, ENCODING.name())){
      while (scanner.hasNextLine()){
        processLine(scanner.nextLine());
      }      
    }
  }


  protected void processLine(String aLine){
    //use a second Scanner to parse the content of each line 
    Scanner scanner = new Scanner(aLine);
    scanner.useDelimiter("=");
    if (scanner.hasNext()){
      //assumes the line has a certain structure
      String name = scanner.next();
      String value = scanner.next();
      log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()));
    }
    else {
      log("Empty or invalid line. Unable to process.");
    }
  }

  // PRIVATE 
  private final Path fFilePath;
  private final static Charset ENCODING = StandardCharsets.UTF_8;  

  private static void log(Object aObject){
    System.out.println(String.valueOf(aObject));
  }

  private String quote(String aText){
    String QUOTE = "'";
    return QUOTE + aText + QUOTE;
  }
} 

Upvotes: 0

Views: 183

Answers (2)

Syam S
Syam S

Reputation: 8499

Your processLine() is expecting a "name=value" pair. And as MightyPork said you are checking hasNext() once, and then read twice. So if that line does not have an = symbol this will break as scanner wont get the next() token. You should add two hasNext() checks. Ideally you dont need a scanner here. Since you are always expecting two tokens delimited by = you can simply rely on java.util.StringTokenizer as

protected void processLine(String aLine){
    StringTokenizer st = new StringTokenizer(aLine, "=");
    if(st.countTokens() == 2) {
        log("Name is : " + quote(st.nextToken().trim()) + ", and Value is : " + quote(st.nextToken().trim()));
    } else {
        log("Empty or invalid line. Unable to process.");
    }
}

Upvotes: 1

ProgrammingIsAwsome
ProgrammingIsAwsome

Reputation: 1129

As the stacktrace indicates, the exception was thrown when scanner.next() was called

at java.util.Scanner.next(Scanner.java:1416)

if (scanner.hasNext()){
      //assumes the line has a certain structure
      String name = scanner.next(); // checked by hasNext()
      String value = scanner.next(); // not checked by hasNext()
      log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()));
}

The error must be in the second .next(). You check if the scanner has a next token, but you call .next() twice. So I assume there is 1 token left and you read twice. Also from the API the next() method:

Throws:
    NoSuchElementException - if no more tokens are available
    IllegalStateException - if this scanner is closed

You can check that easily by adding a System.out.println statement and check what's the last one before the exception (after the first or second call of next())

Upvotes: 0

Related Questions