实验五 输入输出流
一、实验概述
本次上机实验围绕 Java 输入输出字符流完成举重成绩自动统计工具,分为两个核心类:Fenxi.java负责文本数字提取求和,AnalysisResult.java完成文件读取、成绩计算、结果追加写入文件全流程。通过缓冲字符流实现文本文件高效读写,结合正则与字符串分割完成成绩数值解析,完整落地文件 IO 业务场景。
二、整体解题思路
1. 需求拆解
- 读取本地
score.txt举重原始成绩文本,逐行处理; - 提取每行文字中所有数字(支持小数成绩),自动累加计算总成绩;
- 原始文本拼接总成绩后控制台打印;
- 将处理后的完整数据追加写入新文件
socreAnalysis.txt,多次运行不覆盖历史数据; - 捕获 IO 读写异常,保证程序健壮性。
2. 分层实现思路
(1)数值解析层:Fenxi 工具类
- 正则表达式
[^0123456789.]匹配所有非数字、非小数点字符; - 将所有无关字符统一替换为分隔符
*; - 使用
StringTokenizer按分隔符拆分纯数字字符串; - 循环转换为 double 类型累加,返回该行总成绩。
(2)文件 IO 业务层:AnalysisResult 主类
- 底层文件流:
FileReader读取源文件,FileWriter(file,true)开启追加模式输出; - 缓冲包装:用
BufferedReader、BufferedWriter封装底层文件流,提供readLine()按行读取、newLine()换行等便捷方法; - 循环逐行读取文件,调用工具类计算总分,拼接文本后输出控制台 + 写入目标文件;
- 流关闭:读写完成手动关闭缓冲流释放资源;
- 异常捕获:捕获
IOException打印异常信息,避免程序直接崩溃。
3. 填空逻辑推导(原题 4 处代码填空)
- 【代码 1】
new FileWriter(fWrite, true):第二个参数 true 代表追加写入,满足题目追加要求; - 【代码 2】
new BufferedWriter(out):缓冲输出流必须接收 Writer 子类对象做底层流; - 【代码 3】
new FileReader(fRead):文件字符输入流,继承自 Reader 抽象类; - 【代码 4】
new BufferedReader(in):缓冲输入流包装 Reader,实现按行读取。
三、完整示例代码
1. Fenxi.java(数字解析工具类)
import java.util.*; public class Fenxi { public static double getTotalScore(String s) { //匹配所有非数字字符 String regex="[^0123456789.]"; String digitMess=s.replaceAll(regex,"*"); StringTokenizer fenxi = new StringTokenizer(digitMess,"*"); double totalScore=0; while(fenxi.hasMoreTokens()){ double score = Double.parseDouble(fenxi.nextToken()); totalScore = totalScore+score; } return totalScore; } }2. AnalysisResult.java(文件读写主程序)
import java.io.*; import java.util.*; public class AnalysisResult { public static void main(String args[]) { File fRead = new File("score.txt"); File fWrite = new File("socreAnalysis.txt"); try { //【代码1】追加模式文件字符输出流 Writer out = new FileWriter(fWrite, true); //【代码2】缓冲输出流包装 BufferedWriter bufferWrite = new BufferedWriter(out); //【代码3】文件字符输入流 Reader in = new FileReader(fRead); //【代码4】缓冲输入流包装 BufferedReader bufferRead = new BufferedReader(in); String str = null; while((str=bufferRead.readLine())!=null) { double totalScore=Fenxi.getTotalScore(str); str = str+" 总成绩:"+totalScore; System.out.println(str); bufferWrite.write(str); bufferWrite.newLine(); } //关闭流 bufferRead.close(); bufferWrite.close(); }catch(IOException e) { System.out.println(e.toString()); } } }3.score.txt![]()
4.运行结果![]()
四、程序创新点
通用数字提取工具,解耦业务逻辑将数字提取、求和逻辑封装独立工具类
Fenxi,和文件 IO 操作完全分离,后续任何文本数字统计场景可直接复用,符合单一职责设计思想。兼容整数 / 小数成绩,修复原代码正则缺陷原题原始正则仅匹配纯数字,未包含小数点,会导致小数拆分错误;优化正则
[^0123456789.]完美适配带小数点的举重成绩,覆盖真实业务数据。追加写入模式,支持多次迭代统计使用
FileWriter(file,true)开启文件追加,重复运行程序不会覆盖已有统计结果,适合分批录入成绩、持续汇总的使用场景。缓冲流分层包装,兼顾性能与易用性底层使用基础文件流操作磁盘,上层缓冲流封装
readLine()、newLine()等便捷 API,相比原生单字符读写大幅提升大文本文件读写性能。文本无关性解析,不限制文本格式无需固定文本分隔符,无论文字、符号如何混杂,均可自动过滤所有非数字内容提取分数,不局限于举重成绩单,可拓展到成绩单、账单、日志等数字提取场景。
五、实验心得体会
1. 技术知识点收获
- 分清字节流与字符流适用场景:处理中文文本文件优先使用
Reader/Writer字符流,避免中文乱码;图片、视频等二进制文件才使用InputStream/OutputStream字节流。 - 缓冲流是 IO 优化核心:基础文件流单次读写效率极低,
BufferedReader/BufferedWriter内置缓冲区,批量读写磁盘,处理多行文本必须使用。 - 文件追加写入关键:
FileWriter第二个布尔参数控制覆盖 / 追加模式,日常日志、统计记录业务几乎都使用追加模式。 - 正则在文本清洗的实用价值:面对混杂文字和数字的不规则文本,正则可以快速过滤无关字符,简化数据提取流程,省去复杂字符串截取逻辑。
- IO 资源释放规范:文件流属于操作系统资源,使用完毕必须手动
close()关闭,否则会占用文件句柄,导致文件无法修改、删除。
2. 踩坑总结
- 最初未注意正则缺失小数点,带小数成绩会解析报错,修正正则后程序才能正常运行;
- 忘记在写入文件后调用
newLine(),所有输出内容会挤在同一行,可读性极差; - 流关闭顺序错误:必须先关闭上层缓冲流,再关闭底层文件流,缓冲流关闭时会自动刷新缓冲区数据到磁盘;
- 未捕获 IO 异常直接编译报错,所有文件读写操作都属于受检异常,必须搭配
try-catch或抛出异常。
3. 拓展思考
本次程序还有优化空间:可以使用 try-with-resources 语法自动关闭流,省去手动close();增加文件不存在判断,提前提示用户创建score.txt;封装配置文件名常量,方便修改文件路径;增加总分排序、平均分统计等拓展功能。通过本次 IO 实验,我理解了 Java 文件操作的分层设计思想,底层基础流负责硬件交互,上层装饰流拓展功能,这种装饰者模式也为后续学习 IO 高级用法打下基础。
