实验简介
通过前面的代码实践,相信大家已经能够流畅地运用Java编程技术完成某些功能的代码实现,并且对程序设计也有了相对清晰的认知。
但是前面的针对WoniuATM的代码有一个明显的问题,就是代码一旦停止运行,所有的操作全部归零。
所以,从本节实验开始我们将着重来探讨Java为我们提供的常用的一些数据持久化的解决方案。本节实验主要为大家介绍文本文件的读写操作。
实验目的
1. 利用Java的文件处理方法完成对文件的读写操作。
2. 理解字节流,字符流,缓冲区操作的文件IO方式。
实验流程
1. 处理文本文件。
Java处理文件通过通过三种方式来完成:
(1) 按字节流处理(InputSteam和OutputSteam或者针对文件的便捷子类FileInputStream和FileOutputStream类),最底层的操作,将文件处理为一个一个的字节(占用1个字节,8位),但是这样的处理方式输出的都是byte类型的数字,人类无法阅读。通常我们用于处理二进制文件,比如压缩包文件,图片文件,视频资料等非文本类文件。关于字节流处理二进制文件,我们将在后续的项目中为大家介绍其具体用法。
(2) 按字符流处理(InputSteamReader和OutputSteamWriter,或者针对文件的便捷子类FileReader和FileWriter):将文本内容处理为文本,就是按一个一个的标准字符输出,可以对其进行字符编码处理。这是人类可理解的输出内容。
(3) 缓冲区输入输出(BufferedReader和BufferedWriter):可以提升读写性能,Java的默认缓冲区大小是8K。读的时候会一直填满缓冲区(或者文件读取完毕),写的时候也是等缓冲区满了之后(或者执行flush操作)才将内容送入内核缓冲区,通常针对较大内容时使用。
上述所有的操作类均位于包“java.io”下面,使用前需要导入相应的包。
2. 创建文本文件。
我们先建立一个普通的文本文件,将其保存在D:\test.txt,内容如下:
PBET教学模式将通过六大核心方法论来更好地完成教学任务,达到真正意义上培养人才的目的: 1)项目驱动:贯穿不同阶段的不同项目,是帮助学员提升的必备武器,项目经验的积累是核心任务。 2)任务驱动:由于项目的长期性将导致学习的反馈周期长,所以项目必须拆分为诸多细分任务进行。 3)团队化培养:传统的教育模式强调的是个人能力的培养。而企业的真实项目更多的是团队作战。 4)对比式教学:通过对比不同技术的体现形式来实现同一功能,帮助学员深层次理解技术的本质。 5)可视化教学:面对比较空洞的概念或编程逻辑等,设计一套可视化的流程与步骤,帮助快速理解。 6)场景式教学:通过事先设定某个特定场景下的特定问题,来探求该场景下的各种可能的解决方案。 |
3. 字节流读文件。
接下来我们利用字节流完成基本的读操作(由于是非人类友好的字节码输出,所以此处不讨论写操作),当然,由于输出的是字节码,与内容中的中文是无法一一对应上的。内容中的一个中文,会占据两个字节码。
public void byteRead() { try { // 指定文件名来实例化一个File对象,用于后续操作 File file = new File("D:\\Test.txt"); InputStream in = new FileInputStream(file); byte buf[] = new byte[(int)file.length()]; // 创建合适文件大小的数组 in.read(buf); // 读取文件中的内容到buf[]数组 in.close(); for (byte b: buf) { System.out.println(b); } } catch (Exception e) { // 如果出现异常,则将异常信息直接输出 e.printStackTrace(); } } |
上述代码的输出结果如下所示:
从输出结果,我们可以看出,由于中文是无法用一个完整的字节码来表示的,所以我们看到了很多负数的存在(由于byte类型的范围是-128~127)。但是大家仔细观察,会发现我们文章内容的前面四个字母是PBET,是一个标准的ASCII码值,所以我们可以看到输出窗口中前面四个正值,对应的是80(P),66(B),69(E),84(T)。
4. 字节流写文件。
另外,对于字节码输出道理类似,重点是需要将待写入的内容转换为byte类型的字节码即可:
public void byteWrite() { try { File file = new File("D:\\Test.txt"); // FileOutputStream的构造方法第二个参数为true,表示在文件内容后面追加内容 OutputStream out = new FileOutputStream(file, true); String content = "这是文件的内容.\r\n"; byte[] buf = content.getBytes(); out.write(buf, 0, buf.length); out.close(); System.out.println("文件内容写入成功."); } catch (Exception e) { System.out.println("文件内容写入失败."); } } |
5. 字符流读文件。
那么我们再来看看,以字符流方式读写的操作,这也是读写文本文件最常用的一种方式:
public void charRead() { File file = new File("D:\\Test.txt"); try{ InputStream in = new FileInputStream(file); // 此处使用InputSteamReader方便设置编码格式,使用FileReader则无此设置 InputStreamReader reader = new InputStreamReader(in, "GBK"); int temp ; while((temp = reader.read()) != -1){ if (((char)temp) != '\r') { System.out.print((char)temp); } } reader.close(); }catch(Exception e){ e.printStackTrace(); } } |
上述代码可以原样还原读取到的文件内容,运行结果如下:
6. 字符流写文件。
当然,对于写操作,与OutputStream的操作完全类似,代码如下:
public void charWrite() { File file = new File("D:\\Test.txt"); try{ OutputStream in = new FileOutputStream(file, true); OutputStreamWriter out = new OutputStreamWriter(in, "GBK"); String content = "这是需要写入的内容.\r\n"; char[] ch = content.toCharArray(); out.write(ch, 0, ch.length); out.flush(); out.close();
}catch(Exception e){ e.printStackTrace(); } } |
7. 缓冲区读写文件。
最后,我们了解一下使用BufferedReader和BufferedWriter如何完成文件的读写操作:
public void bufferedWrite() { try { File file = new File("D:\\Test2.txt"); OutputStream in = new FileOutputStream(file, true); OutputStreamWriter writer = new OutputStreamWriter(in, "GBK"); BufferedWriter bw = new BufferedWriter(writer); String content = "这是缓冲区输出的新内容.\r\n"; bw.write(content, 0, content.length()); bw.flush();// 强制将缓冲区的内容发送出去,不必等到缓冲区满 bw.close();// 关闭流 writer.close(); // 关闭流 in.close();// 关闭流 } catch (Exception e) { e.printStackTrace(); } } |
8. 总结。
其实通过上述三种读写方式的使用,我们不难看出如下规律:
1) 字节流是最小单位,字符流最终在底层仍然需要依赖于字节流,缓冲区读写仍然需要依赖于前两者的操作,是一种层层包裹的特性。
2) 字节流和字符流是按单个字节或字符读取,而缓冲区读则提供了按行读取的方式。
3) 所有的写操作都尽量指定偏移量(write方法的第二个参数)和内容的长度(write方法的第三个参数),当然,我们可以不指定,使用write方法带一个参数的方式也是可以的。
4) 三种方式其操作原理和操作方式差不多,我们应该根据自己的实际需要来决定。
思考练习
1. 请为WoniuATM定义一个文本文件,用于保存用户数据。
2.尝试利用文本文件完成WoniuATM的注册与登录,看看会遇到哪些问题。