文本文件与基于二进制文件的存储的学生管理系统

news/2025/11/25 0:11:12/文章来源:https://www.cnblogs.com/linqr/p/19265962

文本文件与基于二进制文件的存储的学生管理系统


目录
  • 文本文件与基于二进制文件的存储的学生管理系统
    • 一、项目介绍
    • 二、包结构
    • 三、核心代码介绍
      • 3.1 代码展示
      • 3.2 代码分析
      • 3.3 对比分析
    • 四、结果展示
    • 五、过程回顾
      • 5.1 问题一:二进制文件的“空”并非空白
      • 5.2 问题二:二进制文件的追加陷阱

一、项目介绍

本项目旨在对学生管理系统进行优化,重点在于实现数据持久化。我们通过支持文本与二进制两种存储格式,为系统提供了灵活且可靠的长

期数据保存方案。


二、包结构

StudentsManagementSystemProject/
├── src/
│ └── code/
│ ├── Main.java // 程序入口,UI与主业务逻辑
│ ├── Student.java // 学生数据模型
│ ├── StudentManagementSystemInterface.java // 数据操作接口定义
│ ├── File.java // 文件操作工具类
│ ├── StudentManagementSystem1.java // 基于二进制文件的数据管理实现
│ └── StudentManagementSystem.java // 基于文本文件的数据管理实现
├── data.txt // 文本格式数据文件
└── data1.txt // 二进制格式数据文件

三、核心代码介绍

3.1 代码展示

File.java
该类采用了静态工具类模式,将所有文件读写操作封装起来,实现了业务逻辑与文件操作的解耦

点击查看代码
package code;import java.io.*;
import java.util.ArrayList;
import java.util.List;public class File {public static void appendStudentToTextFile(String filename,String data) {try(FileOutputStream fos = new FileOutputStream(filename,true);OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");BufferedWriter bw = new BufferedWriter(osw)) {bw.write(data);} catch (IOException e) {System.err.println("追加学生到文本文件失败: " + filename);e.printStackTrace();}}public static void writeAllStudentsToTextFile(String filename,List<Student> students) {try(FileOutputStream fos = new FileOutputStream(filename);OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");BufferedWriter bw = new BufferedWriter(osw)) {for(Student s : students) {bw.write(s.StringBuild());}} catch (IOException e) {System.err.println("写入所有学生到文本文件失败: " + filename);e.printStackTrace();}}public static List<Student> readAllStudentsFromTextFile(String filename) {List<Student> students = new ArrayList<>();try (FileInputStream fis = new FileInputStream(filename);InputStreamReader isr = new InputStreamReader(fis, "UTF-8");BufferedReader br = new BufferedReader(isr)) {String line;while ((line = br.readLine()) != null) {String[] parts = line.split(",");if (parts.length == 6) {Student s = new Student(parts[0], Integer.parseInt(parts[1]), parts[2], parts[3], parts[4], Double.parseDouble(parts[5]));students.add(s);}}} catch (IOException e) {System.err.println("从文本文件读取学生失败: " + filename);e.printStackTrace();}return students;}public static void writeAllStudentsToBinaryFile(String filename,List<Student> students) {try (FileOutputStream fos = new FileOutputStream(filename);BufferedOutputStream bos = new BufferedOutputStream(fos);ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(students);} catch (IOException e) {System.err.println("写入所有学生到二进制文件失败: " + filename);e.printStackTrace();}}public static List<Student> readAllStudentsFromBinaryFile(String filename){List<Student> students= new ArrayList<>();try (FileInputStream fis = new FileInputStream(filename);BufferedInputStream bis = new BufferedInputStream(fis);ObjectInputStream ois = new ObjectInputStream(bis)) {students = (List<Student>) ois.readObject();} catch (EOFException e) {//空白}catch (IOException | ClassNotFoundException e) {System.err.println("从二进制文件读取学生失败: " + filename);e.printStackTrace();}return students;}
}

3.2 代码分析

  1. 静态工具类模式

  2. 装饰器模式在IO流中的应用

  • FileOutputStream: 打开一个到文件的连接,并以字节的形式向文件中写入原始数据

  • OutputStreamWriter: 是一个字符到字节的桥梁,它装饰了 FileOutputStream,使其具备了处理字符的能力

  • BufferedWriter: 修饰了 OutputStreamWriter ,为其增加了缓冲区

  1. Java序列化机制
  • ObjectOutputStream: 将Java对象序列化,并写入到二进制文件中

  • ObjectInputStream: 反序列化的核心,将之前通过 ObjectOutputStream 序列化的字节流还原成原始的Java对象

3.3 对比分析

对比 文本文件 二进制文件
读取方式 人类可读,需要用文本编辑器或按字符编码读取 机器可读,人眼看过去是乱码,必须用专门的程序按二进制格式解析
文件形态 由字符编码(如ASCII, UTF-8)构成,内容是字符序列 由比特流构成,内容是字节序列,形态完全由程序定义
存储效率 较低 ,数字等类型需转为字符串,占用更多空间 非常高,数据按内存格式存储,紧凑无冗余
追加操作 天然支持,每行独立,追加不影响旧数据。 严格禁止。会破坏文件结构,导致读取失败

四、结果展示

  • 文本文件存储 (data.txt)
    数据以CSV格式存储,结构清晰,易于人工查看和编辑。

image

  • 二进制文件存储 (data1.txt)
    数据以二进制形式存储,内容无法直接阅读,但保证了数据的高效与安全。

image

五、过程回顾

5.1 问题一:二进制文件的“空”并非空白

现象:删除所有数据后,二进制文件大小不为零

分析与反思:

二进制序列化文件并非在无数据时变为空白。ObjectOutputStream 在创建或覆盖文件时,会首先写入一个魔数和版本标识符作为文件头。

这个文件头是反序列化时识别文件格式的依据,因此一个“空”的二进制文件实际上包含了元数据,而非零字节。

image

5.2 问题二:二进制文件的追加陷阱

现象:模仿文本文件追加数据后,读取时抛出 StreamCorruptedException

分析与反思:

在实现二进制文件存储时,一个常见的误区是模仿文本文件的追加模式。然而,这种做法对于Java序列化文件是致命的。

ObjectOutputStream 在初始化时会向文件写入一个序列化协议头(包含魔数和版本号)。当使用追加模式时,每次写入都会在文件末尾重

复添加这个协议头,从而在数据流中制造了非法的“断点”。这导致 ObjectInputStream 在反序列化时因无法解析预期的对象数据而抛出

StreamCorruptedException,使得整个文件数据无法被正确读取。

解决方案:采用“读-改-写”模式。每次更新数据时,都需将文件全部内容读入内存,修改后,再完整地覆盖写回文件。这确保了文件始终只有一个合法的文件头。

a4c7591710fa71c6e8c3c352e05de4ad

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/975433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 中grep命令在文本中匹配单个的字母

001、 grep命令匹配单个的字母[root@pc1 test]# ls a.txt [root@pc1 test]# cat a.txt ## 测试数据 >chr1 xxx CATCTCCCTTAGTGTTGTCCTGAATTGCTNCTACCAGTCTGCTCTGTGTCTTTCAGGGGGACNNNNNNNNNNNNNNNNNNN NNNNNNN…

Docker Compose 安装问题排查全记录(WSL2 Ubuntu 22.04 环境)

Docker Compose 安装问题排查全记录(WSL2 Ubuntu 22.04 环境)Docker Compose 安装问题排查全记录(WSL2 Ubuntu 22.04 环境) 一、核心问题 在 WSL2 下的 Ubuntu 22.04 系统中,始终无法通过 docker compose 命令调用…

一些 DS

如题。 登山计划给定两个长为 \(n\) 的序列 \(a,b\),\(Q\) 次询问,给定 \(L,R,k\),求: \[\min_{L \leq l \leq r \leq R \wedge r-l+1=k} |\min_{i=l}^{r} a_i- \min_{i=l}^{r} b_i| \]\(n \leq 2\times 10^5,Q \…

newDay22

1.今天弄uml建模软件给我整麻爪了,下载的时候老是报错,建模的时候还对不上教学,探索了半天,剩下的时间就是上课和背单词了 2.明天练练Javaweb什么的 3.Javaweb使用还是太不熟练了,必须得多练练了

B4324 双向链表

点击查看代码 #include<bits/stdc++.h>using namespace std;const int N=500005; int l[N],r[N]; int n,m; bool del[N];void insert(int x,int y) {r[x]=r[y],l[x]=y;l[r[y]]=x,r[y]=x; }void remove(int x) {r…

系列最便宜!苹果iPhone 17e要来了:60Hz低刷灵动岛屏幕

系列最便宜!苹果iPhone 17e要来了:60Hz低刷灵动岛屏幕Posted on 2025-11-24 23:55 lzhdim 阅读(0) 评论(0) 收藏 举报据9to5mac报道,苹果将在2026年第一季度推出多款廉价产品,其中包括搭载A18 Pro的MacBook、…

Codeforces Round 1065 (Div. 3)

A. Shizuku Hoshikawa and Farm Legsvoid solve(){int n;cin >> n;if(n % 2){cout << 0 << endl;return ;}int cnt = 0;for(int i = 0; i <= n / 2; ++i){if((n - 2 * i) % 4 == 0) cnt++;}cout …

代码随想录算法训练营第四天:链表part02

代码随想录算法训练营第四天:链表part0224. 两两交换链表中的节点 leetcode链接:https://leetcode.cn/problems/swap-nodes-in-pairs/description/ 题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表…

CF2027A-Rectangle Arrangement

CF2027A-Rectangle Arrangement 题目大意 一个无限大的平面上,给你 \(n\) 个矩形,你可以在平面上任意放置矩形,要求最小矩形覆盖周长。 题解 考虑贪心做法,将所有矩形左下角都放在 \((0,0)\) 上。记录最长的 \(x\)…

线段树全家桶

非常好线段树。加 ※ 的是开始不会,讲了之后才会的题。 CSES 1648- Dynamic Range Sum Queries给定一个包含 \(n\) 个整数的数组,需要处理 \(q\) 次查询 查询有两种类型:1 k u:将位置 \(k\) 的值更新为 \(u\) 2 a …

用 Node.js 实现英文数字验证码识别

验证码识别在自动化测试、信息提取等领域具有实际价值。本文介绍如何通过 Node.js 和 Tesseract.js 库实现一个简单的英文数字验证码识别程序。 一、技术选型与准备 所需工具 Node.js(建议版本 ≥ 14) Tesseract.js(…

用 Rust 和 Tesseract OCR 实现英文数字验证码识别

验证码识别作为图像处理和字符识别的典型应用,常见于自动化测试、数据采集等场景。本文将介绍如何使用 Rust 编写一个简单的 CLI 工具,结合 Tesseract OCR 引擎识别英文数字验证码。 一、环境准备安装 Rust访问 http…

在Java中调用第三方接口并返回第三方页面

在Java中调用第三方接口并返回第三方页面通常涉及到以下几个步骤:‌发送HTTP请求‌:可以使用多种库来发送HTTP请求,如HttpURLConnection、HttpClient(Apache HttpClient 或 Java 11中的HttpClient)等。‌处理响应…

251124省运会结束啦

周一,天气晴朗,还挺热的

用 C# 和 Tesseract 实现英文数字验证码识别

验证码识别是一项常见的图像处理任务,尤其在自动化测试和数据采集场景中非常实用。本文将介绍如何在 C# 环境下,结合 Tesseract OCR 完成英文数字验证码的自动识别。 一、开发环境准备安装 Visual Studio建议使用 Vi…

有了TCP为什么还需要HTTP?再用RPC?这次彻底讲明白了

记得刚工作那会儿,第一次接触RPC概念时,我内心满是疑惑——明明HTTP用得好好的,为什么要搞出个RPC?直到参与了几个微服务项目后,我才真正能理解它们各自的价值。今天,就让我们一起理清这些协议之间的关系。掘金原…

11.24午夜盘思

1、大盘无忧; 2、情绪方面:中水渔业7连板,如果午后没有打开涨停爆量,当然可以当做空间突破,但打开了涨停,说明连板的接力没那么疯狂,我看了一下连板的晋级率,并没有特别高,所以连板是否宽容,还需要再看一天,…

Spring AI 代码分析(七)--文档的处理

文档处理能力分析 请关注微信公众号:阿呆-bot 1. 工程结构概览 Spring AI 提供了完整的文档处理能力,包括文档读取、文本分块和预处理。这些能力是 RAG 应用的基础。 document-readers/ # 文档读取器…

Java调用第三方接口的方法

.方式一:通过JDK网络类Java.net.HttpURLConnection (1)HttpClientUtil工具类 public class HttpClientUtil { //以post方式调用对方接口方法 public static String doPost(String pathUrl, String data){ …

2025留学代写危机应对指南:5家靠谱机构助你重返校园

2025留学代写危机应对指南:5家靠谱机构助你重返校园留学期间因代写被抓,不仅可能面临挂科、处分,更会影响签证合法性与学业连续性,严重时甚至被遣返。这类危机的处理需精准把握海外院校学术诚信政策、申诉流程及沟…