简体   繁体   English

使用 Scanner.useDelimiter() 和 hasNextLine() 从文件中读取 - NoSuchElementException

[英]Reading from the file with Scanner.useDelimiter() and hasNextLine() - NoSuchElementException

When I try to load the data from the textfile , with data like this当我尝试从文本文件加载数据时,数据如下

java;sdf;2.0;3.0;
cpp;sdks;24.6;89.0;

I'm getting the NoSuchElementException with this code.我用这段代码得到了NoSuchElementException

public void loadFile() {
  Scanner scan = null;  
  int n = 0;
  try {
     scan = new Scanner(new File(this.filename)).useDelimiter(";");
     this.items.clear();
     
     while (scan.hasNextLine()) {
        String name = scan.next();
        String barcode = scan.next();
        double unitPrice = scan.nextDouble();
        double shipCost = scan.nextDouble();

        Product newProduct = new Product(name, barcode, unitPrice, shipCost);
        this.items.add(newProduct);
        n++;
     }
  } 
  catch (IOException e) {
     System.err.println("Caught IOException: " + e.getMessage());
  } catch (InputMismatchException e) {
     System.err.println("Caught InputMismatchException: " + e.getMessage());
     System.out.println(n + " products loaded!");
  } catch (NoSuchElementException e) {
     System.err.println("Attempt to read past end of file");
  } catch (IllegalStateException e) {
     System.err.println("Attempt to read a closed file");
  } finally {
     if (scan != null)
        scan.close();
  }
}

hasNextLine() method waits unitl there is no nextLine but hasNext() waits until there is next token hasNextLine() 方法等待直到没有 nextLine 但 hasNext() 等待直到有下一个标记

For solution perspective use:对于解决方案的角度使用:

 while (scan.hasNext()) {
            String name = scan.next();
            String barcode = scan.next();
            double unitPrice = scan.nextDouble();
            double shipCost = scan.nextDouble();

            System.out.println(name);

            n++;
         }

This will solve your problem这将解决您的问题

There are several approaches how you can solve this.有几种方法可以解决这个问题。

1. Advance to the next line when all token on the current line have been read. 1.当前行的所有token都读完后,前进到下一行。

For that, add the line scan.nextLine() at the end of the loop .为此,在循环的末尾添加行scan.nextLine() Method nextLine() will return the whole current line (that value will be omitted) and will set the scanners position at the beginning of the next line.方法nextLine()将返回整个当前行(该值将被省略)并将在下一行的开头设置扫描仪 position。

while (scan.hasNextLine()) {
    // reading tokens and creating new Product

    scan.nextLine();
}

2. Change the condition in the while loop to scan.hasNext() . 2.while循环中的条件更改scan.hasNext() So that it'll check whether more token exists.这样它将检查是否存在更多令牌。

But another problem will arise: stating from the second item all item names will contain a new line character ( \n ) at the beginning.但是会出现另一个问题:从第二个项目开始,所有项目名称都将在开头包含一个换行符( \n )。

To handle it, you can either apply strip() on a name , change the delimiter to "[;\\r\\n]+" (with that every new line character \n and carriage return \r` character as well as semicolon will be omitted.要处理它,您可以在name上应用strip() ,将分隔符更改为"[;\\r\\n]+" (with that every new line character \n and carriage return \r` 字符以及分号将被省略。

can = new Scanner(new File(this.filename)).useDelimiter("[;\\r\\n]+");
this.items.clear();
            
while (scan.hasNext()) {
    // code inside the loop remains the same
}

The drawback of this approach : condition scan.hasNext() that check existence of a single token doesn't clearly show the intention to read the line comprised of four tokens.这种方法的缺点:检查单个标记是否存在的条件scan.hasNext()没有清楚地表明读取由四个标记组成的行的意图。

3. The last option is to read the file line by line with scan.nextLine() and then apply split(";") on it, which will give an array of strings. 3.最后一个选项是使用scan.nextLine()逐行读取文件,然后对其应用split(";") ,这将给出一个字符串数组。

This solution might look a bit more tedious because it'll require to handle the splitting to parse double values manually.这个解决方案可能看起来有点乏味,因为它需要处理拆分以手动解析double精度值。

while (scan.hasNextLine()) {
    String[] line = scan.nextLine().split(";");
    String name = line[0];
    String barcode = line[1];
    double unitPrice = Double.parseDouble(line[2]);
    double shipCost = Double.parseDouble(line[3]);

    Product newProduct = new Product(name, barcode, unitPrice, shipCost);
    this.items.add(newProduct);
}

All solutions above are tested with the provided file-example and a dummy Product class.以上所有解决方案均使用提供的文件示例和虚拟Product class 进行了测试。

Output ( items list contents) Outputitems清单内容)

[Product{name='java', barcode='sdf', unitPrice=2.0, shipCost=3.0}, Product{name='cpp', barcode='sdks', unitPrice=24.6, shipCost=89.0}]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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