《Java程序案例教程》课件第10章_第1页
《Java程序案例教程》课件第10章_第2页
《Java程序案例教程》课件第10章_第3页
《Java程序案例教程》课件第10章_第4页
《Java程序案例教程》课件第10章_第5页
已阅读5页,还剩125页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第10章文件(IO)操作10.1File类

10.2RandomAccessFile类

10.3流类

10.4字符编码

10.5对象序列化

10.1File类

File类是IO包中唯一代表磁盘文件本身的对象,它定义了一些与平台无关的方法来操纵文件。通过调用File类提供的各种方法,能够完成创建、删除文件,重命名文件,判断文件的读/写权限及文件是否存在,设置和查询文件的最近修改时间等操作。Java能正确处理UNIX和Windows/DOS约定的路径分隔符。如果在Windows版本的Java下用斜线( / ),则路径处理依然正确。如果Windows/DOS使用反斜线( \ )的约定,则需要在字符串内使用它的转义序列( \\ )。Java约定用UNIX和URL风格的斜线来作路径分隔符。下面的构造方法可以用来生成File对象:

File(StringdirectoryPath)

这里directoryPath是文件的路径名。

File定义了很多获取File对象标准属性的方法。例如,getName()用于返回文件名,getParent()返回父目录名,exists()方法在文件存在的情况下返回true,反之返回false。然而File类是不对称的,也就是说虽然存在可以验证一个简单文件对象属性的很多方法,但是没有相应的方法来改变这些属性。下例说明了File的几个方法。

【例10-1】FileDemo.java。

10.2RandomAccessFile类

RandomAccessFile类可以说是Java语言中功能最为丰富的文件访问类,它提供了众多文件访问方法。RandomAccessFile类支持“随机访问”方式,可以跳转到文件的任意位置处读/写数据。在要访问一个文件的时候,不想把文件从头读到尾,而是希望像访问一个数据库一样访问一个文本文件,这时使用RandomAccessFile类就是最佳选择。

RandomAccessFile对象类有个位置指示器,指向当前读/写处的位置,当读/写n个字节后,文件指示器将指向这n个字节后的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,可以移动文件指示器到新的位置,随后的读/写操作将从新的位置开始。RandomAccessFile在随机(相对顺序而言)读取数据等长记录格式文件时有很大的优势,但该类仅限于操作文件,不能访问其他IO设备。

有关RandomAccessFile类中的成员方法及使用说明请参阅JDK文档。下面是一个使用RandomAccessFile的例子,该例中向文件中写入三名员工的信息,然后按照第二名员工、第一名员工、第三名员工的先后顺序读出。RandomAccessFile可以以只读或读/写方式打开文件,具体使用哪种方式取决于用户创建RandomAccessFile类对象的构造方法:

newRandomAccessFile(f,"rw"); //读/写方式

newRandomAccessFile(f,"r"); //只读方式当程序需要以读/写的方式打开一个文件时,如果这个文件不存在,则程序会自动创建此文件。这里还需要设计一个类来封装员工信息。一个员工信息就是文件中的一条记录,而且必须保证每条记录在文件中的大小相同,也就是每个员工的姓名字段在文件中的长度是一样的,这样才能够准确定位每条记录在文件中的具体位置。假设name中有8个字符,少于8个则补空格(这里用“\u0000”),多于8个则去掉后面多余的部分。由于年龄是整型数,因此不管这个数有多大,只要它不超过整型数的范围,在内存中都占4个字节大小。

【例10-2】RandomFileDemo.java。上面的程序完成了所要实现的功能,显示出了RandomAccessFile类的作用。String.substring(intbeginIndex,intendIndex)方法可以用于取出一个字符串中的部分子字符串,但要注意的是:子字符串中的第一个字符对应的是原字符串中脚标为beginIndex的字符,但最后的字符对应的是原字符串中脚标为endIndex-1的字符,而不是脚标为endIndex的字符。

案例1随机流

【案例描述】

使用RandAccessFile流读/写文件。

【代码与注释】 10.3流类

Java的流式输入/输出建立在四个抽象类的基础上,这四个抽象类分别是InputStream、OutputStream、Reader和Writer。它们用来创建具体流式子类。尽管程序通过具体子类执行输入/输出操作,但顶层的类定义了所有流类的基本通用功能。InputStream和OutputStream设计成字节流类。Reader和Writer设计为字符流类。字节流类和字符流类形成分离的层次结构。一般来说,处理字符或字符串时应使用字符流类,处理字节或二进制对象时应用字节流类。一般在操作文件流时,不管是字节流还是字符流都可以按照以下方式进行:

(1)使用File类找到一个文件。

(2)通过File类的对象去实例化字节流或字符流的子类。

(3)进行字节(字符)的读/写操作。

(4)关闭文件流。

下面分别介绍字节流和字符流类。

10.3.1字节流

1. InputStream(输入字节流)

InputStream是一个定义了Java流式字节输入模式的抽象类。该类的所有方法在出错条件下都会引发一个IOException异常。表10-1显示了InputStream的方法。表10-1InputStream定义的方法

2. OutputStream(输出字节流)

OutputStream是定义了流式字节输出模式的抽象类。该类的所有方法返回一个void值并且在出错的情况下引发一个IOException异常。表10-2显示了OutputStream定义的方法。表10-2OutputStream定义的方法

3. FileInputStream(文件输入流)

FileInputStream类创建一个能从文件读取字节的InputStream类,它的两个常用的构造方法如下:

FileInputStream(Stringfilepath)

FileInputStream(FilefileObj)

这两个构造方法都能引发FileNotFoundException异常。这里filepath是文件的绝对路径,fileObj是描述该文件的File对象。

下面的例子创建了两个使用同样磁盘文件且各含一个上面所描述的构造方法的FileInput-Stream类:

4. FileOutputStream(文件输出流)

FileOutputStream创建了一个可以向文件写入字节的类OutputStream,它常用的构造方法如下:

FileOutputStream(StringfilePath)

FileOutputStream(FilefileObj)

FileOutputStream(StringfilePath,booleanappend)

它们可以引发IOException或SecurityException异常。这里filePath是文件的绝对路径,fileObj是描述该文件的File对象。如果append为true,则文件以设置搜索路径模式打开。FileOutputStream的创建不依赖于文件是否存在。在创建对象时,FileOutputStream会在打开输出文件之前就创建它。这种情况下如果试图打开一个只读文件,则会引发一个IOException异常。在下面的例子中,用FileOutputStream类向文件中写入一字符串,并用FileInputStream读出写入的内容。

【例10-3】StreamDemo.java。①第8行~第15行通过File类的对象去实例化OutputStream的对象,此时是通过其子类FileOutputStream实例化OutputStream的对象,属于对象的向上转型。

②因为字节流主要以操作byte数组为主,所以程序第17行通过String类中的getBytes()方法将字符串转换成一个byte数组。

③第18行~第26行调用OutputStream类中的write()方法将byte数组中的内容写入到文件中。

④第27行~第34行调用OutputStream类中的close()方法,关闭数据流操作。

(3)从文件中读取内容:

①第37行~第44行通过File类的对象去实例化InputStream的对象,此时通过其子类FileInputStream实例化InputStream的对象,属于对象的向上转型。

②因为字节流主要以操作byte数组为主,所以程序第46行声明一个大小为1024的byte数组,此数组用于存放读入的数据。

③第49行~第56行调用InputStream类中的read()方法将文件中的内容读入到byte数组中,同时返回读入数据的个数。

④第57行~第64行调用InputStream类中的close()方法,关闭数据流操作。

⑤第66行将byte数组转成字符串输出。从上面例子中可以看出,大部分方法在操作时都进行了异常处理,这是因为所使用的方法处都用throws关键字抛出了异常,所以这里需要进行异常捕捉。

10.3.2字符流

1. Reader

Reader是定义Java的流式字符输入模式的抽象类。该类的所有方法在出错情况下都将引发IOException异常。表10-3给出了Reader类定义的方法。表10-3Reader类定义的方法

2. Writer

Writer是定义流式字符输出的抽象类。所有该类的方法都返回一个void值并在出错条件下引发IOException异常。表10-4给出了Writer类定义的方法。表10-4Writer类定义的方法

3. FileReader

FileReader类创建了一个可以读取文件内容的Reader类。它最常用的构造方法如下:

FileReader(StringfilePath)

FileReader(FilefileObj)

上述构造方法都能引发一个FileNotFoundException异常。这里filePath是一个文件的完整路径,fileObj是描述该文件的File对象。

4. FileWriter

FileWriter创建一个可以写文件的Writer类。它最常用的构造方法如下:

FileWriter(StringfilePath)

FileWriter(StringfilePath,booleanappend)

FileWriter(FilefileObj)

上述构造方法可以引发IOException或SecurityException异常。这里,filePath是文件的绝对路径,fileObj是描述该文件的File对象。如果append为true,则输出是附加到文件尾的。FileWriter类的创建不依赖于文件存在与否。在创建文件之前,FileWriter将在创建对象时打开它作为输出。如果试图打开一个只读文件,将引发一个IOException异常。

【例10-4】CharDemo.java。输出结果:

HelloWorld!!!

程序说明:

此程序也同样分为两部分:一部分是向文件中写入内容(第8行~第34行),另一部分是从文件中读取内容(第37行~第64行)。

(1)程序第6行通过一个File类找到C盘下的一个temp.txt文件。

(2)向文件写入内容。

①第8行~第15行通过File类的对象去实例化Writer的对象,此时是通过其子类FileWriter实例化Writer对象,属于对象的向上转型。②因为字符流主要以操作字符为主,所以程序第17行声明一个String类的对象str。

③第18行~第26行调用Writer类中的write()方法将字符串中的内容写入到文件中。

④第27行~第34行调用Writer类中的close()方法,关闭数据流操作。

(3)从文件中读入内容。

①第37行~第44行通过File类的对象去实例化Reader的对象,此时是通过其子类FileReader实例化Reader对象,属于对象的向上转型。②因为字节流主要以操作char数组为主,所以程序第46行声明一个大小为1024的char数组,此数组用于存放读入的数据。

③第48行~第56行调用Reader类中的read()方法将文件中的内容读入到char数组中,同时返回读入数据的个数。

④第57行~第64行调用Reader类中的close()方法,关闭数据流操作。

⑤第66行将char数组转成字符串输出。可以将该例第27行到第34行注释掉,也就是说在向文件写入内容之后不关闭文件,这时再打开文件,可以发现文件中没有任何内容,这是为什么呢?从JDK文档之中查找FileWriter类,如图10-1所示。图10-1FileWriter类10.3.3管道流

管道流的主要作用是连接两个线程间的通信。管道流也分为字节流(PipedInputStream、PipedOutputStream)与字符流(PipedReader、PipedWriter)两种类型。本节主要讲解PipedInputStream与PipedOutputStream。

一个PipedInputStream对象必须和一个PipedOutputStream对象进行连接而产生一个通信管道,PipedOutputStream可以向管道中写入数据,PipedInputStream可以从管道中读取PipedOutputStream写入的数据。如图10-2所示,这两个类主要用来完成线程之间的通信,一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据。图10-2管道流程序说明:

(1)第8行和第9行分别声明了Sender和Receiver的实例化对象,之后返回各自的管道输出流及管道输入流对象,通过管道输出流的connect方法,将两个管道连接在一起,最后分别启动线程。

(2)第22~42行声明一个Sender类,此类继承了Thread类,所以此类复写了Runnable接口之中的run()方法。程序第24行声明一个PipedOutputStream对象out,此对象用于发送信息。

(3)第43~66行声明一个Receiver类,此类继承了Thread类,所以此类复写了Runnable接口中的run()方法。程序第45行声明了一个PipedInputStream对象in,此对象用于接收其他线程发来的信息。10.3.4ByteArrayInputStream与ByteArrayOutputStream

ByteArrayInputStream是输入流的一种实现,它有两个构造函数,每个构造函数都需要一个字节数组来作为其数据源:

ByteArrayInputStream(byte[]buf)

ByteArrayInputStream(byte[]buf,intoffse,intlength)

如果程序在运行过程中要产生一些临时文件,可以采用虚拟文件方式实现。JDK中提供了ByteArrayInputStream和ByteArrayOutputStream两个类,可实现类似于内存虚拟文件的功能。

【例10-6】ByteArrayDemo.java。10.3.5System.in和System.out

为了支持标准输入/输出设备,Java定义了两个特殊的流对象:System.in和System.out。System.in对应键盘,是InputStream类型的,程序使用System.in可以读取从键盘上输入的数据;System.out对应显示器,是PrintStream类型的,PrintStream是OutputStream的一个子类,程序使用System.out可以将数据输出到显示器上。键盘可以被当做一个特殊的输入流,显示器可以被当做一个特殊的输出流。10.3.6打印流

PrintStream类提供了一系列print和println方法,可以实现将基本数据类型的格式转化成字符串输出。在前面的程序中大量用到“System.out.println”语句中的System.out就是PrintStream类的一个实例对象。PrintStream有下面几个构造方法:

PrintStream(OutputStreamout)

PrintStream(OutputStreamout,booleanautoflush)

PrintStream(OutputStreamout,booleanautoflush,Stringencoding)

其中,autoflush控制在Java中遇到换行符(\n)时是否自动清空缓冲区,encoding指定编码方式。关于编码方式,本章在后面有详细的介绍。println方法与print方法的区别是:前者会在打印完的内容后再多打印一个换行符(\n),所以println()等于print("\n")。

Java的PrintStream对象具有多个重载的print和println方法,它们可输出各种类型(包括Object)的数据。对于基本数据类型的数据,print和println方法会先将它们转换成字符串的形式然后再输出,而不是输出原始的字节内容,如整数221的打印结果是字符“2”、“2”、“1”所组合成的一个字符串,而不是整数221在内存中的原始字节数据。对于一个非基本数据类型的对象,print和println方法会先调用对象的toString方法,然后输出toString方法所返回的字符串。

IO包中提供了一个与PrintStream对应的PrintWriter类。PrintWriter类有下列几个构造方法:

PrintWriter(OutputStream)

PrintWriter(OutputStream,boolean)

PrintWriter(Writer)

PrintWriter(Writer,boolean)

PrintWriter即使遇到换行符(\n)也不会自动清空缓冲区,只有在设置了autoflush模式下使用了println方法后才自动清空缓冲区。PrintWriter相对PrintStream最有利的一个地方就是:println方法的行为在Windows的文本换行是“\r\n”,而Linux下的文本换行是“\n”。如果希望程序能够生成与平台相关的文本换行,而不是在各种平台下都用“\n”作为文本换行,那么就应该使用PrintWriter的println方法。PrintWriter的println方法能根据不同的操作系统而生成相应的换行符。

下例通过PrintWriter类向屏幕上打印信息。

【例10-7】SystemPrintDemo.java。程序说明:第10行通过FileWriter类实例化PrintWriter,此时PrintWriter类的实例化对象out就具备了向文件输出信息的能力,所以在第17行调用print()方法时就会将内容输出到文件之中。图10-3FilePrint输出结果10.3.7DataInputStream与DataOutputStream

DataInputStream与DataOutputStream提供了与平台无关的数据操作,通常会先通过DataOutputStream按照一定的格式输出,再通过DataInputStream按照一定格式读入。由于可以得到Java的各种基本类型甚至字符串,因此对得到的数据便可以方便地进行处理。这在通过协议传输信息的网络上是非常适用的。例如,用户的定单用如下格式储存为order.txt文件:10.3.8合并流

采用SequenceInputStream类可以实现两个文件的合并操作,如图10-4所示。图10-4合并流操作图10-5SequenceDemo输出结果10.3.9字节流与字符流的转换

前面已经讲过,Java支持字节流和字符流,但有时需要字节流和字符流之间的转换。InputStreamReader和OutputStreamWriter这两个类是实现字节流和字符流之间转换的类,InputStreamReader可以将一个字节流中的字节解码成字符,OuputStreamWriter可以将写入的字符编码成字节后写入一个字节流。

InputStreamReader有两个主要的构造函数:程序说明:

(1)第5行、第6行为BufferedReader对象实例化,因为现在需要从键盘输入数据,所以需要使用System.in进行实例化,但System.in是InputStream类型,所以使用InputStreamReader类将字节流转换成字符流,之后将字符流放入到了BufferedReader之中。

(2)第13行通过BufferedReader类中的readLine()方法,等待键盘的输入数据。

(3)第21行通过Integer类将输入的字符串转换成基本数据类型中的整型。

(4)第22行将输入的数字加一。

(5)第23行输出修改后的数据。10.3.10IO包中的类层次关系图

1.字节输入流(InputStream)

InputStream类的层次结构如图10-6所示。图10-6InputStream类的层次结构图

2.字节输出流(OutputStream)

OutputStream类的层次结构如图10-7所示。图10-7OutputStream类的层次结构图

3.字符输入流(Reader)

Reader类的层次结构如图10-8所示。图10-8Reader类的层次结构图

4.字符输出流(Writer)

Writer类的层次结构如图10-9所示。图10-9Writer类的层次结构图案例2缓冲流案例

【案例描述】

使用文件字符输入、输出流读/写文件。

【代码与注释】

test.txt文档中的数据如下:

1.北京奥运会是什么时间开幕的?

A. 2008-08-08 B. 2008-08-01

C. 2008-10-01 D. 2008-07-08

------A------

2.下列哪个国家不属于亚洲?

A.沙特 B.印度 C.巴西 D.越南

------C------

3. 2010年世界杯是在哪个国家举行的?

A.美国 B.英国 C.南非 D.巴西

------C-----

4.下列哪种动物属于猫科动物?

A.鬣狗 B.犀牛 C.大象 D.狮子

-----D------

10.4字符编码

最初计算机的使用是在美国,当时所用到的字符也就是现在键盘上的一些符号和少数几个特殊的符号,一个字节所能表示的数字范围足以容纳所有的字符,实际上表示这些字符的数字的字节最高位(bit)都为0。也就是说,这些数字都在0到127之间,如字符a对应数字97,字符b对应数字98等。这种字符与数字对应的编码规则被称为ASCII码(美国标准信息交换码)。随着计算机在其他国家的逐渐应用和普及,许多国家都把本地的字符集引入了计算机,同时对字符的编码规则进行了适当调整。以中文为例,一个字节所能表示的数字范围是不能容纳所有的中文汉字的。中国大陆将每一个中文字符都用两个字节的数字来表示,原有的ASCII码字符的编码保持不变。中国大陆为每一个中文字符都指定了一个对应的数字,并作为标准的编码固定了下来,这套编码规则称为GBK(国标码)。后来又在GBK的基础上对更多的中文字符(包括繁体)进行了编码。新的编码系统就是GB2312,而GBK则是GB2312的子集。

在一个国家的本地化系统中出现的一个字符,通过电子邮件传送到另外一个国家的本地化系统中,看到的就不是那个原始字符了,而是另外那个国家的一个字符或乱码,因为计算机里面并没有真正的字符,字符都是以数字的形式存在的,通过邮件传送一个字符,实际上传送的是这个字符对应的编码数字。同一个数字在不同的国家和地区代表的很可能是不同的符号。随着世界各国的交往越来越密切,全球一体化的趋势越来越明显,人们不可能完全忘记母语,都去使用英文。当前在不同的国家和地区间交换的电子文档越来越多,特别是人们开发的应用软件都希望能走出国门、走向世界。可见,各个国家和地区都使用各自不同的本地化字符编码,已经给生活和工作带来了很多不方便,严重制约了国家和地区间在计算机使用和技术方面的交流。

为了解决各个国家和地区使用各自不同的本地化字符编码带来的不便,人们将全世界所有的符号进行了统一编码,称之为Unicode编码。长期养成的保守习惯不可能一下子就改变过来,特别是不可能完全推翻那些已经存在的运行良好的系统。新开发的软件要做到瞻前顾后,既能够在存在的系统上运行,又便于以后的战略扩张和适应新的形势。当前,Unicode一统天下的局面暂时还难以形成,在相当长的一段时期内,人们看到的都是本地化字符编码与Unicode编码共存的景象。既然本地化字符编码与Unicode编码共存,那就少不了涉及两者之间的转化问题,在Java中字符使用的都是Unicode编码,Java技术在通过Unicode保证跨平台特性的前提下也支持了全扩展的本地平台字符集,而显示输出和键盘输入都采用本地编码。下面通过范例来介绍字符乱码问题。在这里使用String类中的getBytes()方法,为字符进行编码转换。输出结果如图10-10所

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论