一、IO流基础:
IO流的作用 :用于读写文件、网络等数据,程序运行在内存中,输入流(I)将数据读入内存,输出流(O)将内存数据写出到磁盘或网络。IO流的应用场景 :包括读写文件(如记事本保存和打开文件)、游戏分数存储、文件拷贝、网络通信(消息发送和接收)等,是数据通信的基础技术。IO流的分类 :按方向分为输入流和输出流,按内容分为字节流和字符流。字节流以字节为单位,适合操作所有类型文件(如图片、文本复制);字符流以字符为单位,仅适合操作纯文本文件(如TXT、Java文件)。IO流的四大流 :包括字节输入流(从磁盘或网络以字节形式读数据到内存)、字节输出流(将程序数据以字节形式输出到磁盘或网络)、字符输入流(以字符形式读数据到内存)、字符输出流(将字符数据输出到外部),分别由Java的InputStream、OutputStream、Reader、Writer类代表。
二、文件字节输入流:
IO流体系分类及抽象类特点 :IO流分为字节输入流、字节输出流、字符输入流和字符输出流四大体系,对应的代表类均为抽象类,不能直接使用,需使用其实现类,如FileInputStream(文件字节输入流)、FileOutputStream(文件字节输出流)等。文件字节输入流的作用 :用于将磁盘文件中的数据以字节形式读入内存,不能读取网络数据。文件字节输入流的构造器 :可通过文件对象或文件路径创建流管道,与目标文件接通,其中直接使用文件路径的方式更常用,因为无需构建文件对象,较为方便。文件字节输入流的read方法 :有两种读取方式,一种是每次读一个字节并返回,无字节可读时返回-1;另一种是使用字节数组读取,相当于用桶来装字节,这种方式读取速度更快。每次读一个字节的代码实现及问题 :通过循环读取,每次将读取的字节存入变量,若不等于-1则输出。该方式存在性能较差的问题,且读取汉字时会因截断字节导致乱码,不过作为入门代码,有助于理解IO流的基本思想。每次读多个字节的代码实现及问题 :定义字节数组用于装字节,定义变量记录每次读取的字节数,通过循环读取。此方式能提升性能,减少硬盘与内存的交互次数,但读取中文时若字节数组大小设置不当,仍可能截断汉字字节导致乱码。一次性读取全部字节的方法及适用场景 :使用readAllBytes方法可一次性读完文件的全部字节,能避免读取汉字时乱码,但用合读取小文,若文件过大*会,字节部组占用载内存过多而导致内存溢出。字节流与字符流的适用场景 :读文本内容适合用字符流,因其按字符读取,不会出现乱码;字节流适合用于数据转移,如文件复制,将字节数据读出来转移到其他地方。
三、文件字节输出流:
FileOutputStream的作用 :以内存为基准,将内存中的字节数据写入磁盘文件。构造器及数据写入特点 :可通过文件对象或路径构建管道,默认会清空并覆盖原文件数据,若在构造器中添加参数true则可实现数据追加。写数据的方法 :有三种,分别是写一个字节、写一个字节数组、写字节数组的一部分。写单个字节时,若写入像汉字这样的多字节数据会因只写第一个字节而导致乱码;写字节数组时,可先将字符串通过getBytes()编码成字节数组再写入;写字节数组部分时,需指定起始位置和写入长度。实现换行的方式 :通过写入"\r\n"的字节数组来实现换行,因为"\r\n"兼容性好,能在Windows等多个平台使用,且写入时要先将其转成字节数组。使用流的注意事项 :流使用完后要调用close()方法关闭,以释放内存与磁盘之间总线等底层硬件资源,提升整体性能。总结与后续 :创建字节输出流管道需new FileOutputStream对象,追加数据要在构造器中声明参数true;写数据方法有写单个字节、字节数组及部分字节数组;换行需将"\r\n"转成字节数组写入;下节课将利用文件字节输入流和输出流实现文件复制。
四、字节流进行文件复制及关闭资源:
字节流适合文件复制的原因 :计算机中所有文件底层都是字节组成,字节流可一字不漏转移全部字节,只要复制前后文件格式一致就不会有问题,适合复制图片、视频、TXT等各种文件。字节流复制文件的步骤 :先确定源文件和目标文件路径,创建文件字节输入流与源文件接通,创建文件字节输出流与目标文件接通,定义字节数组作为“桶”,从输入流读字节到数组,再从数组写入输出流,直到读完所有字节。传统关闭资源方式的问题 :在复制代码中若中间出现异常,程序跳走会导致输入输出流未关闭,存在资源未释放的风险。try catch finally关闭资源 :将代码放try catch块,finally块无论try代码正常执行还是异常都会执行,可在finally中关闭资源;但变量在try块内是局部的,需在try外定义并初始化为null,关闭时要判断是否为null,且关闭操作可能抛异常,需再用try catch处理,代码较臃肿。try with resource关闭资源 :JDK7新增方式,将资源定义在try后的小括号中,用完会自动调用close方法关闭资源,简洁优雅;资源需实现Closeable或AutoCloseable接口,如FileInputStream、FileOutputStream等字节流类都实现了这些接口,可作为资源放入。
五、字符流FileReader和FileWrite:
字符流介绍 :字符流适合读取文本文件内容,每次读取字符,其核心实现类为文件字符输入流FileReader和文件字符输出流FileWriter,开发中常结合多态使用。FileReader的作用与使用 :以内存为基准,将磁盘文件中的字符读入内存,通过构造器与文件接通,提供read()方法读单个字符(返回字符编号,无字符返回-1)和read(char[])方法读多个字符(返回读取字符数,无字符返回-1),后者性能更高,且读中文不会乱码。FileReader代码演示 :在IDEA中创建类,使用try-with-resources创建FileReader对象并关联文件,通过字符数组读取文件内容,需注意文件编码与代码编码一致,避免乱码。FileWriter的作用与使用 :以内存为基准,将内存中的字符写入磁盘文件,构造器可通向文件对象或路径,提供write(int)、write(String)、write(String, int, int)、write(char[])、write(char[], int, int)等方法写字符,写换行可通过写入"\n"实现。FileWriter追加与刷新 :默认创建的管道是覆盖管道,追加数据需在构造器中传入true;字符输出流写出数据后需刷新或关闭流才能使数据生效,因为数据先写入内存缓冲区,刷新可将缓冲区数据写入文件,关闭流包含刷新操作且关闭后流不可用。字符流与字节流对比 :文件复制用字节流,因其处理所有文件的字节数据;读文本内容用字符流,按字符读取,不会出现乱码。
六、缓冲流相关知识:
缓冲流分类及作用 :缓冲流分为缓冲字节流和缓冲字符流,其中缓冲字节流包括缓冲字节输入流和缓冲字节输出流,缓冲字符流包括缓冲字符输入流和缓冲字符输出流。它们的作用是提高对应低级流的性能,就像给车改装一样,改装后性能明显提高。缓冲字节流提高性能的原理 :以16KB数据为例,用原始字节流读写需32次系统调用,而缓冲字节输入流和输出流自带8KB缓冲池,读时8KB8KB往内存读,写时倒满8KB同步到文件,各只需2次系统调用,总共4次,大幅减少系统调用次数,提高性能。缓冲字节流的使用 :通过构造器包装低级字节流,如用BufferedInputStream包装FileInputStream得到缓冲字节输入流BIS,用BufferedOutputStream包装FileOutputStream得到缓冲字节输出流BOS,然后用BIS读、BOS写,功能不变但性能提升,且源码显示默认缓冲池大小为8192字节即8KB。缓冲字符输入流 :继承Reader,为提高字符输入流性能,原理与缓冲字节流类似,读16K字符时,原始流用1K桶需16次系统调用,缓冲流自带8K桶只需2次。其用法是包装低级字符输入流,还新增按行读的功能readLine,这是读取文本优雅的方案,能避免字符数组读导致的截断问题,可用循环实现按行读取。缓冲字符输出流 :提高字符输出流写数据性能,16K字符用1K桶需16次系统调用,包装成缓冲流后用8K池只需2次。用法是包装原始字符输出流,新增换行功能newLine,比写“\r\n”更优雅,且低级流的特性如追加由高级流决定。
七、性能分析、几种特殊流以及IO框架:
缓冲流与低级流性能对比 :
对比方式 :分别使用低级字节流按单个字节、字节数组形式,高级缓冲字节流按单个字节、字节数组形式复制大视频,统计每种方式的耗时。性能结论 :低级字节流单个字节复制最慢,几乎无法忍受;低级字节流按字节数组形式复制较慢但可接受;高级缓冲字节流单个字节复制也慢,应淘汰;高级缓冲字节流按字节数组形式复制最快。桶大小影响 :将桶加大,低级管道性能可提升,不一定比缓冲管道差;桶并非越大越好,过大占用内存会影响计算机整体性能和其他程序运行。
字符输入转换流 :
作用 :解决不同编码读取乱码问题,先提取文件原始字节流,再按真实字符集编码将其转换成字符输入流。构造器 :第二个构造器可指定编码,将原始字节流转换为字符输入流,避免乱码。
打印流 :
种类 :包括PrintStream(继承字节输出流)和PrintWriter(继承字符输出流)。功能优势 :可更方便、高效地打印数据,写啥就是啥,支持换行,性能较好,API丰富,可通向文件或低级管道。追加数据 :不能在PrintStream或PrintWriter构造器中加参数追加,需包装低级管道并在低级管道后配追加参数。
特殊数据流 :
作用 :允许将数据和类型一并写出去,满足通信时对数据类型的需求。用法 :将特殊数据输出流包装低级字节输出流,可使用writeByte、writeInt、writeDouble、writeUTF等功能;读取时对应使用readByte、readInt、readDouble等,收发要对应,不能跳读。
IO框架 :
框架定义 :预先写好的代码库或工具,以jar包形式体现,简化和加速开发过程。导入步骤 :从官网下载框架,解压后将jar包复制到项目新建的lib文件夹,右键找到Add library将其添加到项目。功能演示 :可完成文件复制、文件夹拷贝、文件删除、指定编码读取文件内容、写入数据等操作,一行代码即可实现,部分功能借鉴JDK 1.7的NIO新IO技术。
八、华容道中添加步数记录和展示:
案例背景与需求 :学完file和IO流后,通过综合案例巩固知识,需在基础班开发的石头迷阵游戏中,增加游戏胜利后最少步数的记录和展示功能,且该数据需长久保存。开发思路分析 :第一步在游戏界面展示历史最少步数信息;第二步创建文件记录历史最少步数;第三步在玩家胜利后,比较当前步数与历史最少步数,若当前步数更少则更新文件;第四步每次启动游戏时显示历史最少步数。界面展示实现 :在界面初始化时,复制当前移动步数组件并修改,用于展示历史最少步数,将历史最少步数定义为全局变量,从文件读取后展示,同时调整展示位置、字体颜色等样式。文件操作实现 :在项目的SRC下创建score.txt文件,初始写入0。编写方法读取文件中的最少步数,使用缓冲字符输入流,读取后转为整数返回;编写方法将步数写入文件,需转为字符串。胜利后步数处理 :玩家胜利后,读取文件中的最少步数,若为0(首次玩),则将当前胜利步数写入文件;若不为0,当前步数小于历史最少步数时也更新文件。启动时展示处理 :启动游戏时,从文件读取最少步数并赋值给全局变量,用于界面展示。同时处理首次玩时的展示问题,可判断若为0则显示“没有历史部署”。功能测试与问题解决 :启动游戏测试功能,若出现展示问题,通过打日志等方式排查,如确保在展示界面前读取最少步数,最终实现功能。