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

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

提问人:Sumitr Banik 提问时间:3/20/2022 最后编辑:Alexander IvanchenkoSumitr Banik 更新时间:3/21/2022 访问量:306

问:

当我尝试从文本文件加载数据时,使用这样的数据

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

我正在用这个代码得到。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();
  }
}
Java Arraylist java.util.scanner 文件处理 nosuchelementexception

评论

0赞 Martin Zeitler 3/21/2022
这回答了你的问题吗?没有这样的元素例外吗?

答:

0赞 Arka Bandyopadhyay 3/20/2022 #1

hasNextLine() 方法等待 unitl 没有 nextLine but hasNext() 等到有下一个令牌

对于解决方案透视图,请使用:

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

            System.out.println(name);

            n++;
         }

这将解决您的问题

评论

0赞 Sumitr Banik 3/21/2022
即使使用 hasNext() 方法,我也会得到 NoSuchElementException
0赞 Arka Bandyopadhyay 4/6/2022
在我的本地机器上运行良好
0赞 Alexander Ivanchenko 3/21/2022 #2

有几种方法可以解决这个问题。

1. 当当前行上的所有令牌都已读取完毕后,前进到下一行。

为此,请在循环末尾添加该行。Method 将返回整行当前行(该值将被省略),并将扫描仪位置设置在下一行的开头。scan.nextLine()nextLine()

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

    scan.nextLine();
}

2. 将循环中的条件更改为 。这样它就会检查是否存在更多令牌。whilescan.hasNext()

但是会出现另一个问题:从第二开始声明所有项目名称将在开头包含一个新行字符 ()。\n

要处理它,您可以应用名称,将分隔符更改为 \n\r' 字符以及省略分号。strip()"[;\\r\\n]+" (with that every new line character and carriage return

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

这种方法的缺点是:检查单个标记是否存在,不能清楚地显示读取由四个标记组成的行的意图。scan.hasNext()

3.最后一个选项是逐行读取文件,然后对其应用,这将给出一个字符串数组。scan.nextLine()split(";")

此解决方案可能看起来有点乏味,因为它需要手动处理拆分以分析值。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);
}

上述所有解决方案都使用提供的文件示例和虚拟类进行测试。Product

输出(列表内容)items

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

评论

0赞 Sumitr Banik 3/21/2022
第三个选项奏效了,非常感谢!