简体   繁体   中英

Error when reading file into 2D array

I have the following code which tries to determine the dimensions of a file, but each time it executes through there is this error:

Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)

I'm unaware why this is occurring. Can anyone help debug the issue? And explain why it is happening?

public void loadDistances(String fname) throws Exception {
    String file = fname;
    File f = new File(file);
    Scanner in = null;

    try {
        in = new Scanner(f);
    }
    catch (FileNotFoundException ex) {
        System.out.println("Can't find file " + file);
        System.exit(1);
    }

    int rows = 0;
    int cols = 0;
    int elements = 0;

    while(in.hasNext()){ 
        while(in.next() != null){
            System.out.println(elements++);
        }
        in.nextLine(); 
        rows++;
    }
    in.close();

    cols = (elements + 1) / rows;

    // for debug purposes
    System.out.println(rows);
    System.out.println(cols);
}

Which reads in this file

0 2 3.0
1 0 2.0
2 1 7.0
2 3 1.0
3 0 6.0

// Checking for suggested answer

    int tokens = 0;
    String line;
    Scanner tokenScanner;
    Scanner fileScanner;
    Scanner lineScanner;

    while(fileScanner.hasNextLine()){
        line = fileScanner.nextLine();
        lineScanner.nextLine() = line;
        while(lineScanner.hasNext()){
            tokens++;
        }
        rows++;
    }

You assign no data to your variables at all in your scanning loop, and not only that, but you read from the Scanner twice while checking it for data only once , a dangerous thing to do.

while(in.hasNext()){                 // **** checking once ****
    while(in.next() != null){        // **** read in and waste a token here!
        System.out.println(elements++);
    }
    in.nextLine();   // **** read in and waste a line here
    rows++;
}
in.close();

I would:

  • Use two Scanner variables, one, fileScanner, to read in each line of text in the file,...
  • And one called lineScanner to read in each token on the line.
  • I'd use an outer while loop, that checks fileScanner.hasNextLine() , and then calls nextLine() to read the line into a String, say called line .
  • I'd then create a new Scanner with the line of String created, and assign it into a lineScanner variable.
  • I'd use an inner while loop that loops while lineScanner.hasNext() , and reads in the data into your your variables.
  • I'd close the inner lineScanner at the end of the outer while loop so as not to waste resources.

Alternatively, you could use String#split(...) to split the tokens in the line read in, and then parse the Strings into numbers. For example,

public List<RowData> loadDistances(String fname)
     throws FileNotFoundException, NumberFormatException {
  File file = new File(fname);
  Scanner fileScanner = new Scanner(file);
  List<RowData> rowList = new ArrayList<RowData>();

  while (fileScanner.hasNextLine()) {
     String line = fileScanner.nextLine();
     String[] tokens = line.split("\\s+");
     if (tokens.length != 3) {
        // throw some custom exception
     }

     int rowNumber = Integer.parseInt(tokens[0].trim());
     int xData = Integer.parseInt(tokens[1].trim());
     double yData = Double.parseDouble(tokens[2].trim());
     rowList.add(new RowData(rowNumber, xData, yData));
  }

  if (fileScanner != null) {
     fileScanner.close();
  }

  return rowList;
}

Edit
By using a line Scanner, I recommend creating a second Scanner, passing in the line obtained from the first Scanner, and extracting data from this second Scanner. You could use a while loop if you didn't know how many tokens to expect, but your data appears to be well defined, with each line holding an int, int, and double, and we can use this information to help us extract the proper data. You could use code something like this:

 // use previous same code as above except in the while loop:
 while (fileScanner.hasNextLine()) {
     String line = fileScanner.nextLine(); // get line
     Scanner lineScanner = new Scanner(line);  // create Scanner with it
     int rowNumber = 0;
     int xData = 0;
     double yData = 0.0;

     if (lineScanner.hasNextInt()) {
        rowNumber = lineScanner.nextInt();
     } else {
        // throw a custom exception since int not found
     }
     if (lineScanner.hasNextInt()) {
        xData = lineScanner.nextInt();
     } else {
        // throw a custom exception since int not found
     }
     if (lineScanner.hasNextDouble()) {
        yData = lineScanner.nextDouble();
     } else {
        // throw a custom exception since double not found
     }

     rowList.add(new RowData(rowNumber, xData, yData));

     if (lineScanner != null) {
        lineScanner.close();
     }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM