Java 文件读取与数据解析:从文本文件构建学生对象教程

胖墨酱_2771

胖墨酱_2771

2025-10-15

813人浏览

原创

Java 文件读取与数据解析:从文本文件构建学生对象教程

本教程详细讲解如何在 java 中读取文本文件,并解析其中的结构化数据(如学生姓名和成绩)以创建对应的 java 对象。文章对比了两种核心方法:使用 `scanner` 自定义分隔符和结合 `scanner` 逐行读取与 `string.split()`,并提供了详细的代码示例、注意事项以及如何将解析数据集成到自定义 `student` 类中。

在 Java 应用程序开发中,从外部文本文件读取并解析结构化数据是一个常见的需求。例如,我们可能需要从一个包含学生姓名和多门成绩的文本文件中提取信息,然后将其转化为 Java 对象,以便后续进行排序、分析或存储。本文将深入探讨两种主要的 Java 文件读取和数据解析策略,并指导您如何将这些数据封装到自定义的 Student 类中。

文本文件格式示例

假设我们有一个名为 main.txt 的文本文件,其内容包含学生姓名和四门课程的成绩,数据之间以逗号和空格分隔,每行代表一个学生的信息:

John Doe, 30, 25, 70, 10
Jane Doe, 33, 20, 80, 15
Christian Pulisic, 70, 60, 50, 20

我们的目标是读取这些数据,将姓名作为字符串,成绩作为整数,并最终创建 Student 对象。

方法一:使用 Scanner 自定义分隔符

java.util.Scanner 类提供了一种方便的方式来解析基本类型和字符串。通过设置自定义分隔符,我们可以让 Scanner 自动按照特定模式分割输入流中的数据。

核心思想

此方法的核心在于 scan.useDelimiter()。我们需要定义一个正则表达式,它能匹配数据字段之间的分隔符以及行尾的换行符。

  1. 正确的分隔符: 观察示例文件,数据字段之间是 ", "(逗号后跟一个空格),而不是单纯的 ,。
  2. 处理行尾: R 是一个特殊的正则表达式,用于匹配任何类型的行结束符( , , )。
  3. 组合分隔符: 使用 | (或) 运算符将多个分隔符组合起来,即 \R|,。

代码示例

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;

// 假设 Student 类已定义
// class Student {
//     String name;
//     List<integer> grades;
//     public Student(String name, List<integer> grades) {
//         this.name = name;
//         this.grades = grades;
//     }
//     @Override
//     public String toString() {
//         return "Name: " + name + ", Grades: " + grades;
//     }
// }

public class StudentDataReaderDelimiter {

    public static void main(String[] args) {
        // 使用 try-with-resources 确保 Scanner 资源被正确关闭
        try (Scanner scan = new Scanner(new File("main.txt"))) {
            // 设置分隔符为换行符或 ", "
            scan.useDelimiter("\R|, ");

            List<student> students = new ArrayList();

            while (scan.hasNext()) {
                try {
                    String name = scan.next();
                    List<integer> grades = new ArrayList();
                    for (int i = 0; i <h4>优缺点分析</h4>
<ul>
<li>
<strong>优点:</strong><ul>
<li>代码简洁,一旦分隔符设置正确,Scanner 会自动处理字段的提取。</li>
<li>对于数据格式相对一致,且字段数量固定的文件,此方法非常高效。</li>
<li>在某些情况下,即使数据分布在多行,只要分隔符匹配,也能正确解析。</li>
</ul>
</li>
<li>
<strong>缺点:</strong><ul>
<li>
<strong>数据验证不严格:</strong> 很难在读取过程中验证每个学生是否恰好有固定数量的字段。如果某行数据不完整或多余,可能会导致解析错误或将下一个学生的数据误认为当前学生的字段。</li>
<li>
<strong>错误处理复杂:</strong> 当出现格式错误时,很难精确地定位到错误的行并跳过,因为 Scanner 已经将整个文件看作一个连续的 token 流。</li>
</ul>
</li>
</ul>
<h3>方法二:逐行读取与 String.split() 结合</h3>
<p>这种方法通常被认为是处理结构化文本文件更健壮和可控的方式。它将文件读取和行内解析分为两个独立步骤。</p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill11083" title="Java调试"><img
														src="https://img.php.cn/upload/skill/001/246/273/6adaf20dbae7c507.jpg" alt="Java调试" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/xiazai/skill11083" title="Java调试" class="overflowclass">Java调试</a>
													<p class="overflowclass">通过 JDWP 实现 Java 远程调试:连接远程 JVM、设置断点、单步执行代码、查看变量值、获取调用栈。适用于需要调试远程 Java 应用、排查运行时状态、追踪代码执行流程的场景。
术语注解
JDWP:Java Debug Wire Protocol,Java 调试有线协议(Java 远程调试底层通信协议)
remote JVM:远程 Java 虚拟机
step through code:代码单步调试(步入 / 步过 / 步出调试)
inspect variables:变量查看 / 变量检视
stac</p>
												</div>
												<a rel="nofollow" href="/xiazai/skill11083" title="Java调试" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div>
<h4>核心思想</h4>
<ol>
<li>
<strong>逐行读取:</strong> 使用 Scanner 或 BufferedReader 逐行读取文件内容。</li>
<li>
<strong>行内解析:</strong> 对每一行读取到的字符串,使用 String.split() 方法根据指定的分隔符将其分割成一个<a style="color:#f60; text-decoration:underline;" title="字符串数组" href="https://m.php.cn/zt/52359.html" target="_blank">字符串数组</a>(tokens)。</li>
<li>
<strong>类型转换与验证:</strong> 遍历字符串数组,将字符串类型的成绩转换为整数,并进行必要的格式验证。</li>
</ol>
<h4>代码示例</h4>
<pre class="brush:php;toolbar:false;">import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

// 假设 Student 类已定义
// class Student {
//     String name;
//     List<integer> grades;
//     public Student(String name, List<integer> grades) {
//         this.name = name;
//         this.grades = grades;
//     }
//     @Override
//     public String toString() {
//         return "Name: " + name + ", Grades: " + grades;
//     }
// }

public class StudentDataReaderSplit {

    public static void main(String[] args) {
        // 使用 try-with-resources 确保 Scanner 资源被正确关闭
        try (Scanner scan = new Scanner(new File("main.txt"))) {
            List<student> students = new ArrayList();
            int lineNumber = 0;

            while (scan.hasNextLine()) {
                lineNumber++;
                String line = scan.nextLine(); // 读取整行
                String[] tokens = line.split(", "); // 使用 ", " 分割行

                // 验证 token 数量
                if (tokens.length == 5) { // 1个姓名 + 4个成绩 = 5个 token
                    String name = tokens[0];
                    List<integer> grades = new ArrayList();
                    boolean allGradesValid = true;

                    for (int i = 1; i <h4>优缺点分析</h4>
<ul>
<li>
<strong>优点:</strong><ul>
<li>
<strong>强大的数据验证:</strong> 可以轻松地在每行级别进行字段数量、数据类型等验证,从而更准确地识别和处理错误。</li>
<li>
<strong>清晰的错误报告:</strong> 当数据格式不正确时,可以报告具体的行号和错误信息。</li>
<li>
<strong>更好的控制:</strong> 对每一行数据拥有完全的控制权,可以执行更复杂的解析逻辑。</li>
</ul>
</li>
<li>
<strong>缺点:</strong><ul><li>如果单个逻辑记录(如一个学生的所有信息)跨越多行,此方法需要额外的逻辑来拼接这些行。</li></ul>
</li>
</ul>
<h3>构建 Student 类并集成数据</h3>
<p>为了更好地组织和管理解析出的数据,我们应该定义一个 Student 类来封装学生姓名和成绩。</p>
<h4>Student 类定义</h4>
<pre class="brush:php;toolbar:false;">import java.util.List;
import java.util.ArrayList;

public class Student implements Comparable<student> {
    private String name;
    private List<integer> grades;

    public Student(String name, List<integer> grades) {
        this.name = name;
        this.grades = new ArrayList(grades); // 深度拷贝,防止外部修改
    }

    public String getName() {
        return name;
    }

    public List<integer> getGrades() {
        return new ArrayList(grades); // 返回拷贝,防止外部修改
    }

    // 计算平均分(可选)
    public double getAverageGrade() {
        if (grades.isEmpty()) {
            return 0.0;
        }
        int sum = 0;
        for (int grade : grades) {
            sum += grade;
        }
        return (double) sum / grades.size();
    }

    @Override
    public String toString() {
        return "Student [Name=" + name + ", Grades=" + grades + ", Average=" + String.format("%.2f", getAverageGrade()) + "]";
    }

    // 实现 Comparable 接口,用于按姓名字母顺序排序
    @Override
    public int compareTo(Student other) {
        return this.name.compareTo(other.name);
    }
}</integer></integer></integer></student>

在上述的两个数据读取示例中,我们已经将解析出的姓名和成绩列表传递给了 Student 类的构造函数,并创建了 Student 对象。例如,在 StudentDataReaderSplit 类的 main 方法中:

// ... (之前的代码) ...
if (allGradesValid) {
    students.add(new Student(name, grades)); // 创建 Student 对象并添加到列表中
}
// ... (之后的代码) ...

将这些 Student 对象存储在一个 List 中,可以方便地进行后续操作,例如排序:

// 在解析完所有学生数据后
import java.util.Collections; // 导入 Collections 类

// ... (在 main 方法的最后) ...
Collections.sort(students); // 按姓名字母顺序排序学生列表

System.out.println("
--- Sorted Students ---");
for (Student student : students) {
    System.out.println(student);
}

注意事项与最佳实践

  1. 资源管理: 始终确保文件读取器(如 Scanner)在使用完毕后被关闭,以释放系统资源。Java 7 引入的 try-with-resources 语句是处理此问题的最佳方式,它能自动关闭实现了 AutoCloseable 接口的资源。
    try (Scanner scan = new Scanner(new File("main.txt"))) {
        // 文件读取和解析逻辑
    } catch (FileNotFoundException e) {
        // 异常处理
    }
  2. 异常处理:
    • FileNotFoundException: 当指定的文件路径不存在时抛出。务必捕获并处理此异常,告知用户文件缺失。
    • NumberFormatException: 当尝试将非数字字符串转换为整数时抛出(例如,成绩字段包含字母)。在解析成绩时,应捕获此异常,并妥善处理(例如,跳过该条记录,或将成绩设为默认值)。
  3. 数据校验:
    • 在解析前,检查每行数据是否包含预期的字段数量(如方法二中的 tokens.length == 5)。
    • 对数值类型的数据,除了 NumberFormatException,还可以添加业务逻辑上的校验(例如,成绩是否在 0-100 之间)。
  4. 字符编码: 默认情况下,Scanner 使用平台的默认字符集。如果您的文本文件使用了不同的编码(例如 UTF-8),您需要在创建 Scanner 时明确指定:
    Scanner scan = new Scanner(new File("main.txt"), "UTF-8");
  5. 性能考量:
    • 对于小型到中型文件,Scanner 已经足够高效。
    • 对于非常大的文件(GB 级别),考虑使用 BufferedReader 结合 String.split(),因为 BufferedReader 提供了更高效的缓冲读取机制。

总结

在 Java 中读取文本文件并解析结构化数据,主要有两种高效且常用的方法:使用 Scanner 自定义分隔符和结合 Scanner 逐行读取与 String.split()。

  • Scanner 自定义分隔符 适用于数据格式非常固定且字段数量一致的场景,代码简洁。
  • 逐行读取与 String.split() 结合 提供了更精细的控制和更强大的错误处理能力,尤其适用于需要严格验证每行数据格式的场景,是更推荐的通用方法。

无论选择哪种方法,都应遵循 Java 的最佳实践,包括正确的资源管理、健壮的异常处理和详尽的数据校验,以确保程序的稳定性和数据的准确性。通过将解析出的数据封装到如 Student 这样的自定义类中,可以极大地提高代码的可读性、可维护性和数据操作的便利性。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

2023.06.20

4696

8

正则表达式不包含
正则表达式不包含

正则表达式,又称规则表达式,,是一种文本模式,包括普通字符和特殊字符,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式的文本。php中文网给大家带来了有关正则表达式的相关教程以及文章,希望对大家能有所帮助。

2023.07.05

3201

4

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8882

9

java正则表达式匹配字符串
java正则表达式匹配字符串

在Java中,我们可以使用正则表达式来匹配字符串。本专题为大家带来java正则表达式匹配字符串的相关内容,帮助大家解决问题。

2023.08.11

812

5

正则表达式空格
正则表达式空格

正则表达式空格可以用“\s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。本专题为大家提供正则表达式相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.31

520

5

Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

693

12

正则表达式空格如何表示
正则表达式空格如何表示

正则表达式空格可以用“\s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。想了解更多正则表达式空格怎么表示的内容,可以访问下面的文章。

2023.11.17

406

3

正则表达式中如何匹配数字
正则表达式中如何匹配数字

正则表达式中可以通过匹配单个数字、匹配多个数字、匹配固定长度的数字、匹配整数和小数、匹配负数和匹配科学计数法表示的数字的方法匹配数字。更多关于正则表达式的相关知识详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.12.06

739

7

php正则表达式有哪些
php正则表达式有哪些

php正则表达式有"/pattern/"、"^"、"$"、"."、"[]"、"[^]"、"[a-z]"、"[A-Z]"、"[0-9]"、"\d"、"\D"、"\w"、"\W"、&a

2024.02.23

312

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习