java - 我用 Scanner 类读取文件有什么问题?

标签 java exception

每次运行它时,都会给出此消息((InputMismatchException))问题出在哪里?

        File f = new File("nameList.txt");
    try {
        PrintWriter out;
        out = new PrintWriter(f);
        for (int i = 0; i < 4; i++) {
            out.printf("Name : %s Age : %d ", "Rezaee-Hadi", 19);
            out.println("");
        }
        out.close();
    } catch (IOException ex) {
        System.out.println("Exception thrown : " + ex);
    }
    try {
        Scanner in = new Scanner(f);
        String name = in.nextLine();
        int age = in.nextInt();
        for (int i = 0; i < 4; i++) {
            System.out.println(name);
            System.out.println(age);
        }
        in.close();
    } catch (FileNotFoundException ex) {
        System.out.println("Exception thrown : " + ex);
    }

最佳答案

您正在使用以下数据格式创建数据文件:

Name : Rezaee-Hadi Age : 19

现在,(在某种程度上)如何格式化数据文件并不重要,只要您意识到稍后可能需要解析该数据即可。您确实不需要在每个文件行上维护包含数据的 header 。我们已经知道,任何文件行上的第一条数据都是姓名,任何文件行上的第二条数据都是与该姓名相关的人的年龄。因此,以下内容就足够了:

Rezaee-Hadi, 19

如果需要,您可以将 header 放置在数据文件的第一行,以便可以轻松确定每行上的每条数据的相关内容,例如:

Name, Age
Rezaee-Hadi, 19
Fred Flintstone, 32
Tom Jones, 66
John Smith, 54

这实际上是 CSV 数据文件的典型格式。

Keeping with the file data format you are already using:

使用 Scanner#nextLine() 没有任何问题。方法。这是一个很好的方法,但您应该使用 while 循环逐行迭代文件,因为您可能并不总是确切知道文件中包含多少实际数据行,例如:

Scanner in = new Scanner(f);
String dataLine;
while (in.hasNextLine()) {
    dataLine = in.nextLine().trim();
    // Skip Blank Lines
    if (dataLine.equals("")) {
        continue;
    }
    System.out.println(dataLine);
}

这将打印文件中包含的所有数据行。但这并不是你真正想要的。您想要将姓名和年龄与每一行分开,这意味着您需要解析每一行的数据。一种方法(在你的情况下)是这样的:

String dataLine;
Scanner in = new Scanner(f);
while (in.hasNextLine()) {
    dataLine = in.nextLine().trim();
    // Skip Blank Lines
    if (dataLine.equals("")) {
        continue;
    }
    String[] dataParts = dataLine.replace("Name : " , "").split(" Age : ");
    System.out.println("The Person's Name: " + dataParts[0] + System.lineSeparator() 
                     + "The Person's Age:  " + dataParts[1] + System.lineSeparator());
}

在上面的代码中,我们使用 while 循环一次一行地遍历整个数据文件。当每一行被读入 dataLine 字符串变量时,它也会被修剪掉任何前导或尾随空格。通常我们不想要这些。然后我们检查以确保该行不为空。我们通常也不需要这些,在这里我们通过向 while 循环发出继续来跳过这些空行,以便立即启动另一次迭代。如果文件行 line 实际上包含数据,那么它将保存在 dataLine 变量中。

现在我们要解析该数据以检索名称和年龄并将它们放入字符串数组中。我们通过使用String#split()来做到这一点方法,但首先我们使用 String#replace() 删除该行的“Name :”部分方法,因为我们不想在解析该行时处理此文本。在 String#split()方法中我们提供了一个用于分割的字符串分隔符,该分隔符是“Age : ”。

String[] dataParts = dataLine.replace("Name : " , "").split(" Age : ");

现在,当解析每一行时,Name 和 Age 将作为位于索引 0 和索引 1 处的元素包含在 dataParts[] 字符串数组中。我们现在使用这些数组元素来显示结果到控制台窗口。

此时,年龄是一个字符串,位于 dataParts[] 数组中的索引 1 处,但您可能希望转换此年龄为整数 (int) 类型值。为此,您可以使用 Integer.parseInt()Integer.valueOf()方法,但在执行此操作之前,您应该验证要传递给这两个方法中的任何一个的字符串确实是字符串数字整数值。为此,您可以使用 String#matches()方法以及一个简单的小Regular Expression (正则表达式):

int age = 0;
if (dataParts[1].matches("\\d+")) {
    age = Integer.parseInt(dataParts[1]);
    // OR  age = Integer.valueOf(dataParts[1]);
    System.out.println("Age = " + age);  
}
else {
    System.out.println("Age is not a numerical value!");  
}

放置在 String#matches() 方法中的正则表达式 "\\d+" 基本上意味着,“所提供的字符串是整数数值的字符串表示形式吗? ?”。如果该方法发现它不是,则返回 boolean 值false。如果发现提供的值是字符串整数数值,则返回 boolean 值 true。这样做可以防止任何 NumberFormatException 的发生。

关于java - 我用 Scanner 类读取文件有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59854681/

相关文章:

C++异常类设计

python - 在没有 "raise"语句的情况下引发 python 异常

java - 如何在Java中按下鼠标按钮时监听鼠标移动事件

java - 对象列表上的 JUnit Mockito ReflectionEquals

java - 接收参数的 CDI 验证

java - 缺少 android 权限时适合抛出什么异常?

c++ - Qt/C++ Exited with code -1073741819(程序崩溃,异常代码为 c0000005)

java - textToBePresentInElement() 不适用于确切的文本

java - 更改 Android 操作栏菜单项的点击图标

vb6 - 如何将exe异常路由回VB6应用程序?