第8章 IO_补充案例

更新时间:2024-05-11 09:04:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

博学谷——让IT教学更简单,让IT学习更有效

第八章 补充案例

案例8-1 FileInputStream读取文件数据

一、案例描述

1、 考核知识点

编 号:00108002

名 称: 字节流读写文件--读取文件

2、 练习目标

? 掌握如何使用FileInputStream字节流读取文件中数据

3、 需求分析

在操作文件时,最常见的就是从文件中读取数据并将数据写入文件,即文件的读写。针对文件的读操作,JDK专门提供了FileInputStream类。为了让初学者掌握FileInputStream字节流的使用,在案例中将针对读取并打印指定文件中的数据进行演示。

4、 设计思路(实现原理)

1) 创建一个文本文件fis.txt,在文件中编辑内容“Welcome to learn IO stream!”。 2) 在同一目录下创建Example01.java文件,编写Example01类。

3) 在main()方法中,通过FileInputStream(String name)构造方法创建文件输入字节流对象,并指

定待读取文件fis.txt的路径。

4) 在while循环条件中使用read()方法每次读取一个字节,同时在循环体中打印每次读取的数据,

当read()方法返回值为-1时表示读取到文件结尾,循环结束。 5) 使用close()方法,关闭流资源。

二、案例实现

import java.io.FileInputStream; import java.io.IOException; public class Example01 {

public static void main(String[] args) throws IOException {

// 创建字节输入流对象

FileInputStream fis = new FileInputStream(\// 读取所有字节 int by = 0;

while ((by = fis.read()) != -1) { }

// 关闭字节输入流 fis.close();

1

System.out.print((char) by);

博学谷——让IT教学更简单,让IT学习更有效

}

}

运行结果如图8-1所示。

图8-1 运行结果

从运行结果可以看出,使用FileInputStream类成功地读取出fis.txt文件中的数据。

三、案例总结

1、通过FileInputStream(String name)构造方法创建FileInputStream对象时,传入的待读取文件的路径,可以是相对路径也可以是绝对路径。

2、在读取文件数据时,必须保证文件是存在并且可读的,否则会抛出文件找不到的异常FileNotFoundException。

3、FileInputStream类有三个重载的read()方法,如果方法返回值为-1,均表示已读取到了文件的结尾。 4、为了使流对象所占用的系统资源得到释放,请记住调用FileInputStream类close()方法关闭字节流。 5、思考一下:修改Example01类,如何实现只读取文件的单个字节?代码如下:

import java.io.FileInputStream; import java.io.IOException; /*

* 读取单个字节 */

public class Example01 { }

public static void main(String[] args) throws IOException { }

// 创建字节输入流对象

FileInputStream fis = new FileInputStream(\// 读取单个字节 int i = fis.read(); System.out.println(i); // 关闭字节输入流 fis.close();

案例8-2 FileOutputStream写入数据

一、案例描述

1、 考核知识点

编 号:00108003

名 称: 字节流读写文件--写入文件

2

博学谷——让IT教学更简单,让IT学习更有效

2、 练习目标

? 掌握如何使用FileOutputStream字节流向文件写入数据

3、 需求分析

与FileInputStream对应的是FileOutputStream,它是操作文件的字节输出流,专门用于把数据写入文件。为了让初学者掌握FileOutputStream字节流的使用,在案例中将通过演示向文本文件写入一段文字来学习。

4、 设计思路(实现原理)

1) 编写Example02类。 2) 在main()方法中,通过FileOutputStream(String name)构造方法创建文件输出字节流对象,并指

定写入的文件路径。

3) 定义一段字符串,并将它转换成byte数组,然后通过write(byte[] b)方法,将byte数组写入到

文件输出流中。

4) 使用FileOutputStream类的close()方法,关闭流资源。

二、案例实现

import java.io.FileOutputStream; import java.io.IOException; public class Example02 { }

public static void main(String[] args) throws IOException { }

// 创建字节输出流对象

FileOutputStream fos = new FileOutputStream(\// 用字符串转换字节数组

byte[] b = \欢迎学习IO流\// 将数组中数据写入文件 fos.write(b); // 关闭输出流 fos.close();

程序运行后,会在当前目录下生成一个新的文本文件fos.txt,文件内容如图8-2所示:

图8-2 fos.txt

从运行结果可以看出,使用FileOutputStream类成功把数据写入文件。

3

博学谷——让IT教学更简单,让IT学习更有效

三、案例总结

1、与FileInputStream读取的文件必须存在不同,FileOutputStream写入数据的文件不必是已存在的,因为该文件会被自动创建。

2、FileOutputStream类有三个重载的write()方法,可以分别向文件中一次写入单个字符、字符数组以及数组的部分数据。

3、思考一下:我们在使用案例中的方式,多次向fos.txt文件中写入不同数据时,发现文件中原有内容被新数据替代了。请问如果希望在原有文件内容之后追加新内容,如何修改Example02类?代码如下:

import java.io.FileOutputStream; import java.io.IOException; public class Example02 { }

public static void main(String[] args) throws IOException { }

// 创建字节输出流对象

FileOutputStream fos = new FileOutputStream(\// 用字符串转换字节数组

byte[] b = \,真的很好玩\// 将数组内容写入文件 fos.write(b); // 关闭输出流 fos.close();

程序运行后,再次打开fos.txt,文件内容如图8-3所示:

图8-3 fos.txt

以上代码中使用了FileOutputStream的另一个构造方法FileOutputStream(String fileName, boolean append) 来创建文件输出流对象,当设置append参数值为true时表示追加内容,从上图可以看出新内容成功追加到原有内容以后。

案例8-3 自定义缓冲区拷贝大文件

一、案例描述

1、 考核知识点

编 号:00108005

名 称: 字节流的缓冲区

2、 练习目标

4

博学谷——让IT教学更简单,让IT学习更有效

? 掌握如何自定义缓冲区

? 掌握如何使用自定义缓冲区读、写文件 ? 了解自定义缓冲区读写的优点

3、 需求分析

操作文件时一个个字节的读写,效率非常低,为了提高效率可以自定义一个字节数组作为缓冲区。为了让初学者掌握如何使用自定义缓冲区读写文件,案例中将演示使用字节流的自定义缓冲区拷贝“IO流.avi”文件到其它目录来学习。

4、 设计思路(实现原理)

1) 在当前目录下创建source和target文件夹,并在source文件夹中存放一个“IO流.avi”文件。 2) 编写Example03类。 3) 在main()方法中,分别创建文件字符输出流和文件字符输入流对象,并指定文件拷贝的源及目

标路径。

4) 自定义一个1024长度的字节数组作为缓冲区,然后通过输入流将源文件数据读取到缓冲区中,

输出流再将缓冲区中数据写入到目标文件中,循环往复直到文件拷贝结束,并计算拷贝文件总耗时。

5) 使用close()方法,关闭流资源。

二、案例实现

import java.io.*;

public class Example03 {

public static void main(String[] args) {

FileInputStream fis = null; FileOutputStream fos = null; try {

// 创建文件字符输出流和文件字符输入流对象

fis = new FileInputStream(\流.avi\fos = new FileOutputStream(\流.avi\// 创建字节数组,用于缓存读取的字节 byte[] bys = new byte[1024]; int len = 0;

long starttime = System.currentTimeMillis();// 获取拷贝文件前的系统时间 // 读取到文件结束时,返回-1

while ((len = fis.read(bys)) != -1) { }

long overtime = System.currentTimeMillis();// 获取拷贝文件结束的系统时间 System.out.println(\拷贝文件消耗的时间为:\毫秒\e.printStackTrace();

throw new RuntimeException(\拷贝文件失败!\

// 将缓冲区中的数据写入文件 fos.write(bys, 0, len);

} catch (IOException e) {

} finally {

5

博学谷——让IT教学更简单,让IT学习更有效

}

}

}

try { } try { }

// 关闭流资源 fos.close();

e.printStackTrace();

throw new RuntimeException(\输出流关闭失败!\// 关闭流资源 fis.close();

e.printStackTrace();

throw new RuntimeException(\输入流关闭失败!\

} catch (IOException e) {

} catch (IOException e) {

程序运行结束后,打开target文件夹,发现source文件夹中的“IO流.avi”文件被成功拷贝到了target文件夹,如图8-4所示。

图8-4 拷贝结果

程序运行结束后,会在命令行窗口输出拷贝文件所消耗的时间,如图8-5所示:

图8-5 运行结果

从运行结果可以看出,使用自定义缓冲区拷贝大文件成功,而且耗时较短。

三、案例总结

1、由于计算机性能等各方面原因,会导致每次拷贝文件所消耗的时间未必相同。 2、在指定文件路径时使用了“\\\\”,这是因为在Windows目录路径基础上使用了转义符“\\”。 3、为了保证IO流的close()方法必须执行,通常将关闭流的操作写在finally代码块中。

4、思考一下:使用自定义缓冲区拷贝文件时效率高耗时短,请修改Example03类,在不使用缓冲区的情况下拷贝文件,打印所消耗的时间,并与使用缓冲区所耗时间比较。代码如下:

import java.io.FileInputStream;

6

博学谷——让IT教学更简单,让IT学习更有效

import java.io.FileOutputStream; import java.io.IOException; public class Example03 { }

public static void main(String[] args) { }

FileInputStream fis = null; FileOutputStream fos = null; try { }

// 创建文件字符输出流和文件字符输入流对象

fis = new FileInputStream(\流.avi\fos = new FileOutputStream(\流.avi\// 创建字节数组,用于缓存读取的字节 int len = 0;

long starttime = System.currentTimeMillis();// 获取拷贝文件前的系统时间 // 读取到文件结束时,返回-1

while ((len = fis.read()) != -1) { }

long overtime = System.currentTimeMillis();// 获取拷贝文件结束的系统时间 System.out.println(\拷贝文件消耗的时间为:\毫秒\e.printStackTrace();

throw new RuntimeException(\拷贝文件失败!\try { } try { }

// 关闭流资源 fos.close();

e.printStackTrace();

throw new RuntimeException(\输出流关闭失败!\// 关闭流资源 fis.close();

e.printStackTrace();

throw new RuntimeException(\输入流关闭失败!\// 将缓冲区中的数据写入文件 fos.write(len);

} catch (IOException e) {

} finally {

} catch (IOException e) {

} catch (IOException e) {

7

博学谷——让IT教学更简单,让IT学习更有效

案例8-4 装饰设计模式的应用

一、案例描述

1、 考核知识点

编 号:00108006 名 称: 装饰设计模式

2、 练习目标

? 了解什么是装饰设计模式 ? 掌握装饰设计模式的应用

3、 需求分析

装饰设计模式是通过包装一个类,动态地增强它的功能的一个设计模式,为了让初学者掌握装饰设计模式的应用,在案例将通过使用NewPerson类装饰Person类,完成为Person类增强“吃饭”功能来学习。

4、 设计思路(实现原理)

1) 编写Person类,定义eat()方法,表示“吃饭”功能

2) 编写NewPerson类,定义一个有参构造方法,通过构造方法可以将Person对象传入该类,在

NewPerson类定义newEat()方法,该方法对“吃饭”功能进行了扩展和增强。

3) 编写Example04测试类,在main()方法中,分别通过Person和NewPerson对象调用装饰前后

的吃饭功能。

二、案例实现

/** * 被装饰类 */

class Person { } /** * 装饰类 */

class NewPerson {

// 装饰类中拥有被装饰类的引用 private Person p;

// 构造方法传入被装饰类的对象 public NewPerson(Person p) { }

8

this.p = p; // 吃饭功能

public void eat(){ }

System.out.println(\正在吃饭\

博学谷——让IT教学更简单,让IT学习更有效

} /**

* 测试类Example04 */

public class Example04 { }

public static void main(String[] args) { }

System.out.println(\装饰前----\Person p = new Person(); p.eat();

System.out.println(\装饰后----\//使用NewPerson类来装修Person类

NewPerson np = new NewPerson(new Person()); np.newEat(); // 通过装饰类增强吃饭功能 public void newEat() { }

System.out.println(\饭前小酒\p.eat();

System.out.println(\抽一根烟\System.out.println(\饭后甜点\

运行结果如图8-6所示。

图8-6 运行结果

从运行结果可以看出,通过装饰设计模式成功增强了“吃饭”功能,达到预期效果。

三、案例总结

1、装饰设计模式具有以下特点:

(1) 装饰对象包含一个被装饰对象的引用。

(2) 装饰对象接受所有来自客户端的请求,再把这些请求转发给被装饰的对象。 (3) 装饰对象可以给被装饰对象增强功能。

(4) 一般情况下装饰和被装饰对象会具有相同的接口。

2、思考一下:装饰设计模式可以通过一个类增强另一个类的功能,而使用继承子类也可以对父类中的功能进行增强,针对增加功能这种情况请问使用装饰设计模式和继承有什么区别。

9

博学谷——让IT教学更简单,让IT学习更有效

案例8-5 字节缓冲流拷贝大文件

一、案例描述

1、 考核知识点

编 号:00108007 名 称: 字节缓冲流

2、 练习目标

? 了解什么是字节缓冲流 ? 了解字节缓冲流的优点

? 掌握如何使用字节缓冲流拷贝文件

3、 需求分析

我们学习过使用自定义缓冲区高效读写文件,其实Java自身也提供了两个带缓冲的字节流,分别是BufferedInputStream和BufferdOutputStream。为了熟悉这两个字节缓冲流的使用,案例中将通过使用字节缓冲流一次读写一个字节数组的方式拷贝文件来学习。

4、 设计思路(实现原理)

1) 在source目录下存放“IO流.avi”文件,并确保target目录下没有上次拷贝遗留的文件。 2) 编写Example05类。在main()方法中,分别创建缓冲字节输出流和缓冲字节输入流对象,并

指定拷贝文件的源及目标路径。

3) 定义一个字节数组作为缓冲区,缓冲输入流将源文件数据读取到缓冲区中,然后缓冲输出流

将缓冲区中数据写入到目标文件中,循环往复直到文件拷贝结束,并计算拷贝文件总耗时。 4) 使用close()方法,关闭流资源。

二、案例实现

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /**

* 字节缓冲流一次读写一个字节数组 */

public class Example05 {

public static void main(String[] args) {

BufferedInputStream bis = null; BufferedOutputStream bos = null; try {

bis = new BufferedInputStream(

new FileInputStream(\流.avi\\流.avi\

10

bos = new BufferedOutputStream(new FileOutputStream(

博学谷——让IT教学更简单,让IT学习更有效

图8-12 运行结果

运行结果显示正常,添加行号输出达到预期。

三、案例总结

setLineNumber()方法设置当前行号,getLineNumber()方法读取当前行号。在案例当前行号初始值设为100,输出时行号却是从101开始的,这是因为LineNumberReader类在读取到换行符('\\n')、回车符('\\r')或者回车后紧跟换行符时,会将行号自动加1。

案例8-9 转换流拷贝文件

一、案例描述

1、 考核知识点

编 号:00108011 名 称: 转换流

2、 练习目标

? 了解什么是转换流

? 掌握如何使用InputStreamReader和OutputStreamWriter

3、 需求分析

有时字节流和字符流之间也需要进行转换,这时就需要用到转换流。在JDK中提供了两个类可以将字节流转换为字符流,它们分别是InputStreamReader和OutputStreamWriter。为了让初学者掌握转换流的使用,案例中将演示通过转换流拷贝文件并转成大写来学习。

4、 设计思路(实现原理)

1) 在source目录下编写“HelloWrold.java”文件,里面有一段HelloWorld程序。 2) 在同一目录下,编写Example09类。

3) 在main()方法中,创建文件字节输入和输出流对象,然后分别使用转换流包装,为提高效率,

最后再通过缓冲流包装。

4) 使用readLine()方法循环一行行读取源文件并转大写写入到目标文件,直至文件末尾。 5) 调用close()方法,关闭流资源。

二、案例实现

import java.io.*;

public class Example10 {

public static void main(String[] args) {

BufferedReader bfr = null;

16

博学谷——让IT教学更简单,让IT学习更有效

}

}

BufferedWriter bfw = null; try {

InputStream in = new FileInputStream(\// 字符的缓冲读取字节,将字节转成字符

InputStreamReader isr = new InputStreamReader(in); // 建立字符流缓冲区对象

bfr = new BufferedReader(isr);

OutputStream out = new FileOutputStream(\// 字符数据,输出到字节,将字符数据转成字节

OutputStreamWriter osw = new OutputStreamWriter(out); // 建立字符流的缓冲区对象

bfw = new BufferedWriter(osw); String line = null;

while ((line = bfr.readLine()) != null) { }

bfw.write(line.toUpperCase()); bfw.newLine();

} catch (IOException e) { }

throw new RuntimeException(\文件拷贝失败!\try { } try { }

if (bfw != null)

bfw.close(); if (bfw != null)

bfr.close();

} finally {

} catch (IOException e) {

e.printStackTrace();

throw new RuntimeException(\输入流关闭失败!\

} catch (IOException e) {

e.printStackTrace();

throw new RuntimeException(\输出流关闭失败!\

程序运行后,分别打开“source”和“target”目录下“HelloWorld.java”文件,结果如图8-13所示:

17

博学谷——让IT教学更简单,让IT学习更有效

图8-13 拷贝结果

从结果可以看出,使用转换流拷贝文件并转大写操作成功。

三、案例总结

在使用转换流时,只能针对操作文本文件的字节流进行转换,如果字节流操作的是一张图片,此时转换为字符流就会造成数据丢失。

案例8-10 对象序列化与反序列化

一、案例描述

1、 考核知识点

编 号:00108013

名 称: ObjectInputStream和ObjectOutputStream类

2、 练习目标

? 了解什么是序列化和反序列化

? 掌握如何使用ObjectInputStream和ObjectOutputStream实现对象的序列化和反序列化

3、 需求分析

使用ObjectOutputStream和ObjectInputStream可以实现对象的序列化和反序列化。为了让初学者掌握这两种类的使用,案例中将通过序列化Person对象到“oos.txt”文件,再反序列化读取该文件获取Person对象数据来学习。

4、 设计思路(实现原理)

1) 编写Person类,实现序列化接口,在类中定义name和age属性,生成get ()和set()方法,并

重写toString()方法。

2) 编写Example10类,在main()方法中通过ObjectOutputStream将赋值后的Person对象序列化

到“oos.txt”文件。

3) 通过ObjectInputStream读取该文件实现Person对象的反序列化,并打印该对象。

二、案例实现

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Example10{

public static void main(String[] args) throws Exception{

// 创建序列化流对象

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(

\

// 创建对象

Person p = new Person(\马云\

18

博学谷——让IT教学更简单,让IT学习更有效

}

import java.io.Serializable;

public class Person implements Serializable { }

private static final long serialVersionUID = 333558257579870816L; private String name; private int age; public Person() { }

public Person(String name, int age) { }

public String getName() { }

public void setName(String name) { }

public int getAge() { }

public void setAge(int age) { }

// 重写toString()方法 public String toString() { }

return \this.age = age; return age; this.name = name; return name; this.name = name; this.age = age; }

// 将Person对象输出到输出流中 oos.writeObject(p); oos.close(); // 创建反序列化流对象

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(

\

// 从oos.txt中读取Person对象 Object obj =ois.readObject(); ois.close();

// 打印反序列化后的对象

System.out.println((Person)obj);

程序运行后,在当前目录下生成了“oos.txt”文件,如图8-14所示:

19

博学谷——让IT教学更简单,让IT学习更有效

图8-14 生成文件

运行结果如图8-15所示。

图8-15 运行结果

三、案例总结

值得注意的是,当对象进行序列化时,必须保证该对象实现Serializable接口,否则程序会出现NotSerializableException异常。

案例8-11 DataInputStream和DataOutputStream

一、案例描述

1、 考核知识点

编 号:00108013

名 称: DataInputStream和DataOutputStream类

2、 练习目标

? 掌握如何使用DataInputStream和DataOutputStream

3、 需求分析

如果只需存储对象的成员数据,这些成员数据的类型又都是基本数据类型,这时就可以使用DataInputStream和DatOutputStream。为了让初学者掌握DataInputStream和DataOutputStream的用法,案例中将演示使用这两个类先向“dos.txt”文件中写入UTF-8的字符串然后再读取来学习。

4、 设计思路(实现原理)

1) 编写Example11类。

2) 在main()方法中通过DataOutputStream向“oos.txt”文件中,写入字符编码为UTF-8的字符串

“你好”。

3) 通过DataInputStream读取文件中该编码的字符串并打印。

20

博学谷——让IT教学更简单,让IT学习更有效

输出流和字节数组输入流。为了让初学者熟悉者两个类,在案例中通过使用这两个类来读取和输出一个字符串数据来演示。

4、 设计思路(实现原理)

1) 编写Example14类

2) 在main()方法中使用ByteArrayInputStream(byte[] buf)构造方法,创建一个字节数组输入流对

象,并将要一段字符串读取到缓冲区数组中

3) 创建一个ByteArrayOutputStream,然后在while循环中,将字节数组输入流缓冲区中数据读取

到输出流缓冲区中

4) 将输出流缓冲区中的数据一次性输出到控制台

二、案例实现

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public class Example14 { }

public static void main(String[] args) { }

//创建一个字节数组输入流,使用缓冲区数组

ByteArrayInputStream bis = new ByteArrayInputStream(

\

//创建一个字节数组输出流

ByteArrayOutputStream bos = new ByteArrayOutputStream(); int by = 0;

//循环读取输入流缓冲区中的数据到输出流缓冲区中 while ((by = bis.read()) != -1) { }

//将缓冲区中的数据一次性输出

System.out.println(bos.toString());

bos.write(by);

程序运行结果如图8-20所示。

图8-20 运行结果

三、案例总结

1、ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。关闭 ByteArrayInputStream是无效的,该类中的方法在关闭此流后仍然可以被调用,而不会产生任何 IOException。

2、ByteArrayOutputStream类实现了一个输出流,其中的数据被写入一个 byte 数组,缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。和ByteArrayInputStream一样,关闭

26

博学谷——让IT教学更简单,让IT学习更有效

ByteArrayOutputStream是无效的,该类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 3、虽然ByteArrayInputStream的缓冲区会根据存入数据的多少而自动变化,但是读取的文件非常大时,就不能使用这个类,否则会造成内存溢出。

案例8-15 CharArrayReader和CharArrayWriter读写操作

一、案例描述

1、 考核知识点

编 号:00108018

名 称: CharArrayReader和CharArrayWriter

2、 练习目标

? 了解CharArrayReader和CharArrayWriter读写的特点

? 掌握如何使用CharArrayReader和CharArrayWriter进行读写操作

3、 需求分析

要想将字符型数据临时存入缓冲区中,可以使用JDK提供的CharArrayReader和CharArrayWriter类,分别表示字符数组输入流和字符数组输出流,它们的功能与ByteArrayInputStream、ByteArrayOutputStream类似,只不过操作的数据是字符。为了让初学者熟悉这两个类的使用,在案例中将通过读取和输出一个文件中的内容来演示。

4、 设计思路(实现原理)

1) 编写一个类Example15 2) 在main()方法中,使用FileReader读取caw.txt文件中的内容,然后创建CharArrayWriter对象,

将读取的内容写入到CharArrayWriter缓冲区。

3) 创建CharArrayReader对象,读取字符数组缓冲区中的数据并打印

二、案例实现

import java.io.*;

public class Example15 {

public static void main(String[] args) throws Exception {

FileReader fr = new FileReader(\创建一个FileReader对象

CharArrayWriter chaw = new CharArrayWriter();// 在内存中创建一个字符数组缓冲区 // 下面的代码是将数据写入缓冲区 int b;

while ((b = fr.read()) != -1) { }

fr.close(); chaw.close();

char[] chs = chaw.toCharArray();// 将缓冲区中的数据转换成字符型数组 CharArrayReader cr = new CharArrayReader(chs);// 读取字符数组中的数据 // 下面的代码是从缓冲区中读取数据,并进行打印

27

chaw.write(b); // 将读取到的字符写入缓冲区

博学谷——让IT教学更简单,让IT学习更有效

}

}

int i = 0;

while ((i = cr.read()) != -1) { }

System.out.println((char) i);

运行结果如图8-21所示。

图8-21 运行结果

三、案例总结

CharArrayReade从字符数组中读取数据,CharArrayWriter是在内存中创建一个字符数组缓冲区,它们的功能与ByteArrayInputStream、ByteArrayOutputStream类似,只不过操作的数据是字符。

案例8-16 SequenceInputStream

一、案例描述

1、 考核知识点

编 号:00108019

名 称: SequenceInputStream

2、 练习目标

? 掌握如何使用SequenceInputStream合并多个流对象

3、 需求分析

如果希望多个流处理数据,这时就需要将这些流进行合并。JDK提供了SequenceInputStream类,它可以将几个输入流串联在一起,合并为一个输入流。为了让初学者掌握SequenceInputStream的用法,案例中使用这个类将读取不同文件的两个输入流合并,并将合并后的数据输出到另一个文件。

4、 设计思路(实现原理)

1) 2) 3) 4)

编写Example16类

在main()方法中分别创建两个读取不同文件的输入流对象

使用SequenceInputStream合并流将这两个输入流对象对象合并 通过文件输出流将合并后的数据写入到另一个文件中

28

博学谷——让IT教学更简单,让IT学习更有效

二、案例实现

import java.io.*;

public class Example16 { }

public static void main(String[] args) throws Exception { }

// 下面的代码是创建了两个流对象fis1、fis2

FileInputStream fis1 = new FileInputStream(\FileInputStream fis2 = new FileInputStream(\// 创建一个序列流,合并两个字节流fis1和fis2

SequenceInputStream sis = new SequenceInputStream(fis1, fis2); FileOutputStream fos = new FileOutputStream(\int len;

byte[] buf = new byte[1024]; // 创建一个1024个字节数组作为缓冲区 // 下面的代码用于循环读取三个流中的文件 while ((len = sis.read(buf)) != -1) { }

sis.close(); fos.close();

fos.write(buf, 0, len); // 将缓冲区中的数据输出

程序运行结果如图8-22所示。

图8-22 运行结果

三、案例总结

1、上述案例中是对两个流进行合并,要对多个流进行合并可以使用SequenceInputStream类的另一个构造方法,具体如下:

SequenceInputStream(Enumeraion e)

2、SequenceInputStream类从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

29

博学谷——让IT教学更简单,让IT学习更有效

案例8-17 File类的常用方法的使用

一、案例描述

1、 考核知识点

编 号:00108020

名 称: File类的常用方法

2、 练习目标

? 掌握File类的构造方法及File对象的创建方式 ? 掌握如何使用File类中的常用方法

3、 需求分析

在开发过程中涉及到文件有关的内容时,我们经常会使用到File类,该类中拥有一系列的方法,对于初学者来说很难弄清它们之间的区别,为了让大家熟悉File类中的常用方法,本案例将演示File类中的方法对文件进行操作来学习方法的使用。

4、 设计思路(实现原理)

1) 编写Example17类

2) 在main()方法中使用File(String parent, String child)构造方法创建File文件对象

3) 使用File类的方法对该文件进行各种操作,包括判断文件是否存在,判断是否是文件,获取

文件名称,获取文件大小,获取最后修改时间等等。

二、案例实现

import java.io.File;

import java.io.IOException; import java.sql.Date;

import java.text.DateFormat; public class Example17 {

public static void main(String[] args) throws IOException {

// 创建File文件对象,表示一个文件

File file = new File(\// 判断文件是否存在

System.out.println(\文件是否存在:\存在\不存在\if (!file.exists()) { }

// 获取文件名称

System.out.println(\文件名称:\// 获取文件的相对路径

System.out.println(\文件的相对路径:\// 获取文件的绝对路径

30

// 如果文件不存在便创建该文件

boolean ifcreat = file.createNewFile();

System.out.println(\文件是否创建成功:\

博学谷——让IT教学更简单,让IT学习更有效

}

}

System.out.println(\文件的绝对路径:\// 获取文件的父路径

System.out.println(\文件的父路径:\// 判断是否是一个绝对路径

System.out.println(file.isAbsolute() ? \是绝对路径\不是绝对路径\// 判断是否是一个隐藏文件

System.out.println(file.isHidden() ? \是隐藏文件\不是隐藏文件\// 判断是否是一个文件

System.out.println(file.isFile() ? \是一个文件\不是一个文件\// 判断是否是一个目录

System.out.println(file.isDirectory() ? \是一个目录\不是一个目录\// 判断文件是否可读

System.out.println(file.canRead() ? \文件可读\文件不可读\// 判断文件是否可写

System.out.println(file.canWrite() ? \文件可写\文件不可写\// 得到文件最后修改时间,并将毫秒数转成日期 long time = file.lastModified(); Date d = new Date(time);

String date = DateFormat.getDateTimeInstance(DateFormat.LONG,

DateFormat.LONG).format(d);

System.out.println(\最后修改时间为:\// 得到文件的大小

System.out.println(\文件大小为:\

程序结果如图8-23所示。

图8-23 运行结果

三、案例总结

1、File类有三个常用构造方法,如下表所示: 方法声明 File(String pathname) 功能描述 通过指定的一个字符串类型的文件路径来创建一个新的File对象 31

博学谷——让IT教学更简单,让IT学习更有效

根据指定的一个字符串类型的父路径和一个字符串类型的子路径(包括文件名称)创建一个File对象 根据指定的File类的父路径和字符串类型的子路径(包括文件名称)创建一个File对象 File(String parent,String child) File(File parent,String child) 针对本案例,这三种常用构造方法创建File对象可以都使用,示例代码如下:

// 方式1: File(String pathname) File file = new File(\

// 方式2: File(String parent,String child) File file = new File(\ // 方式3: File(File parent,String child) File parentfile = new File(\

File file = new File(parentfile, \

2、File类中的createNewFile()方法,当文件存在时不会创建,该方法返回值为false,文件不存在时才创建,如果创建成功,该方法返回值为true。

3、在获取文件的最后修改时间操作中,使用到了DateFormat类,将File类中的lastModified()方法返回的毫秒值转换成了日期,更直观。

4、除了上面案例中演示的方法外,File类中还有其它常用的方法,例如重新命名文件。File类非常重要,常用方法也特别多,建议大家在学习File类的过程中多查看API。

案例8-18 递归遍历目录及其子目录下的文件

一、案例描述

1、 考核知识点

编 号:00108021

名 称: 遍历目录下的文件

2、 练习目标

? 掌握File类中的listFiles()方法的使用

? 掌握如何递归遍历一个目录及其子目录下的文件

3、 需求分析

在一个目录下,除了文件,常常还会有子目录,如果想得到所有子目录下的File类型对象,就需要遍历整个目录及其子目录,在File类中提供了listFiles(),该方法返回一个File对象数组,由于元素中可能还有子目录需要遍历,因此需要使用递归。为了让大家熟悉遍历目录下的文件的操作,本案例将使用listFiles()方法和递归方式遍历目录及其子目录下的文件来演示。

4、 设计思路(实现原理)

1) 编写Example18类

2) 在main()方法中使用File(String pathname)构造方法创建File文件对象,给定待遍历的目录的

路径

3) 编写fileDir()方法,并在该方法中使用File类的listFiles()方法获得目录下所有文件的数组,遍

历数组,判断如果是目录,使用递归方式继续遍历,如果是文件则打印输出该文件的绝对路径

4) 在main()方法中调用fileDir()方法,并传入待遍历的File对象

32

博学谷——让IT教学更简单,让IT学习更有效

二、案例实现

import java.io.File; public class Example18 { }

public static void main(String[] args) { }

public static void fileDir(File dir) { }

File[] files = dir.listFiles(); // 获得表示目录下所有文件的数组 for (File file : files) { }

if (file.isDirectory()) { }

System.out.println(file.getAbsolutePath());

// 输出文件的绝对路径

fileDir(file);

// 如果是目录,递归调用fileDir() // 遍历所有的子目录和文件

File file = new File(\fileDir(file);

// 调用fileDir删除方法

// 创建一个代表目录的File对象

程序结果如图8-24所示。

图8-24 运行结果

三、案例总结

1、File类中有一个list()方法,该方法用于遍历某个指定目录下的所有文件的名称,返回值类型是String[]类型,和它不同的是,listFiles()方法返回值类型是File[]类型。list()还有一个重载方法list(FilenameFilter filter),其中FilenameFilter是文件过滤器,在文件过滤器对象的accept()方法中可以对文件进行过滤操作,例如遍历指定扩展名的文件等。

2、在案例中由于每次遍历文件的操作是相同的,因此fileDir()方法中可以使用递归的方式,即自身调用自身的情况。

33

博学谷——让IT教学更简单,让IT学习更有效

案例8-19 使用delete()方法删除目录

一、案例描述

1、 考核知识点

编 号:00108022

名 称: 删除文件及目录

2、 练习目标

? 掌握File类中的delete ()方法的使用 ? 掌握如何删除一个文件及目录

3、 需求分析

在操作文件时,经常需要删除一个目录下的某个文件或者删除整个目录,这时可以使用File类提供的delete()方法。为了让初学者掌握如何删除文件及目录,案例中将使用delete()方法对指定目录进行删除来演示。

4、 设计思路(实现原理)

1) 编写Example19类

2) 在main()方法中使用File(String pathname)构造方法创建File文件对象,指定删除的目录为C

盘下名为“temp”的文件夹

3) 使用File类的exists()方法判断该文件是否存在,如果存在就使用delete()方法对其进行删除操

二、案例实现

import java.io.*; class Example19 { }

public static void main(String[] args) { }

File file = new File(\if (file.exists()) { }

System.out.println(\文件删除成功:\System.out.println(\该文件不存在\}else{

程序运行结果如图8-25所示。

图8-25 运行结果

34

博学谷——让IT教学更简单,让IT学习更有效

三、案例总结

1、delete()方法不仅可以可以删除文件,还删除目录,只是删除目录时,该目录必须为一个空目录,否则删除会失败。思考一下,如果要删除一个不为空的目录,Example19类该怎样修改?

示例代码如下:

import java.io.*;

public class Example19 { }

public static void main(String[] args) { }

public static void deleteDir(File dir) { }

if (dir.exists()) { // 判断传入的File对象是否存在 }

File[] files = dir.listFiles(); // 得到File数组 for (File file : files) { // 遍历所有的子目录和文件 }

// 删除完一个目录里的所有文件后,就删除这个目录 dir.delete();

if (file.isDirectory()) { }

deleteDir(file); // 如果是目录,递归调用deleteDir() // 如果是文件,直接删除 file.delete(); } else {

File file = new File(\创建一个代表目录的File对象 deleteDir(file); // 调用deleteDir删除方法

2、在Java中删除目录是从虚拟机直接删除不走回收站,文件将无法恢复,因此在进行删除操作的时候需要格外小心。

案例8-20 RandomAccessFile随机读写文件

一、案例描述

1、 考核知识点

编 号:00108023

名 称: RandomAccessFile

2、 练习目标

? 掌握如何使用RandomAccessFile随机读写文件

3、 需求分析

文件存取通常是循序的,每在文件中存取一次,文件的读取位置就会相对于目前的位置前进

35

博学谷——让IT教学更简单,让IT学习更有效

一次。然而有时必须指定文件的某个区段进行读取或写入的动作,也就是要能在文件中随意地移动读取位置,这时可以使用RandomAccessFile类。为了让初学者熟悉RandomAccessFile类,案例中将使用该类写入一段字符串并随机读取来演示。

4、 设计思路(实现原理)

1) 编写Example20类

2) 在main()方法中创建RandomAccessFile对象,指定读写的文件为当前目录下的“random.txt”

文件,读写模式为读写(rw)

3) 向文件中写入一段字符串,然后移动文件指针位置再读取

二、案例实现

import java.io.IOException; import java.io.RandomAccessFile; public class Example20 { }

public static void main(String[] args) throws IOException { }

RandomAccessFile raf = new RandomAccessFile(\raf.write(\raf.seek(3);

byte[] buf = new byte[6]; int len = raf.read(buf);

System.out.println(new String(buf,0,len)); raf.close();

程序结果如图8-26所示。

图8-26 运行结果

三、案例总结

RandomAccessFile类有两个构造方法,如下表所示: 方法声明 RandomAccessFile(File file,String mode) RandomAccessFile(String name,String mode) 功能描述 参数file指定被访问的文件 参数name指定被访问文件的路径 其中第二个参数可以指定访问文件的模式,参数mode有四个值,最常用的有两个,分别是““r和“rw”,其中“r”表示以只读的方式打开文件,“rw”表示以“读写”的方式打开文件。

36

博学谷——让IT教学更简单,让IT学习更有效

案例8-21 字符编码和解码

一、案例描述

1、 考核知识点

编 号:00108025

名 称: 字符编码和解码

2、 练习目标

? 掌握如何进行字符编码和解码操作

3、 需求分析

在Java编程中,经常会出现字符转换为字节或者字节转换为字符的操作。为了让初学者掌握字符编码和解码,在案例中对“你好”编码并用另一个编码格式解码来演示。

4、 设计思路(实现原理)

1) 编写Example21类

2) 在main()方法中将“你好”进行编码,转换成gb2312编码格式的字节数组并打印 3) 将字节数组以uft-8编码格式进行解码,转成String类型的数据并打印

二、案例实现

import java.util.Arrays; public class Example21 { }

public static void main(String[] args) throws Exception { }

byte[] bytes = \你好\System.out.println(Arrays.toString(bytes)); String s = new String(bytes, \System.out.println(s);

程序结果如图8-27所示。

图8-27 运行结果

三、案例总结

1、字符转成字节的过程称为编码,字节转换为字符的过程称为解码,编码和解码的过程如图8-28所示。

37

博学谷——让IT教学更简单,让IT学习更有效

解码二进制的字节序列编码明文的字符序列 图8-28 编码和解码过程

2、如果编码和解码时使用的码表不一致,可能会造成乱码问题。

38

本文来源:https://www.bwwdw.com/article/qggg.html

Top