Java程序设计基础》第10章:输入输出系统.ppt_第1页
Java程序设计基础》第10章:输入输出系统.ppt_第2页
Java程序设计基础》第10章:输入输出系统.ppt_第3页
Java程序设计基础》第10章:输入输出系统.ppt_第4页
Java程序设计基础》第10章:输入输出系统.ppt_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

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

文档简介

第10章 输入输出系统 学习重点: l输入输出的总体结构 l流的概念 l构建不同的流 第10章 输入输出系统 10.1 输入输出流的概述 10.2 各种流的使用 10.2.1 文件流 10.2.2 管道流 10.2.3 连接文件 10.2.4 过滤流 10.2.5 对象的序列化 10.2.6 随机访问 10.3 练习题 10.1 输入输出流的概述 Java的输入和输出多以流的方式进行的,它的特点是数据的发 送 和获取都是延数据序列顺序进行的,每个数据必须等待它前面的 数 据发送或读入后才能被读写。 l当需要读入数据时,程序先从数据的来源(文件、网络等)打开一个流 ,然后从这个流中顺序读取数据 l当要输出数据时,程序打开一个流,通过这个流向输出目标顺序写入 数据 1. Character流 Character流以Reader(对应输入)和Writer(对应输出)两个类族来实现 , 其中Reader和Writer是输入和输出族的根类 Reader BufferedReader CharArrayReader InputStreamReader FilterReader PipedReader StringReader LineNumberReader FileReader PushbackReader Writer Bufferedwriter CharArraywriter OutputStreamReader FilterWriter PipedWriter StringWriter FilterWriter FileWriter 2. Byte流 传输8位的数据就应用 Byte流,Java库中用InputStream(输入)和 OutputStream(输出)类族中的类来实现8位数据的传输,这些类主要用来 传输二进制数据,如声音和图像,ObjectInputStream ObjectOutputStreamy用来传输对象序列。 3. 关于IO的根类 Reader含有以下读取字符和字符数组的方法: int read() int read(char cbuf) int read(char cbuf, int offset, int length) 而InputStream定义了读取byte型数据的方法如下: int read() int read(byte cbuf) int read(byte cbuf, int offset, int length) Writer方法如下: int write(int c) int write(char cbuf) int write(char cbuf, int offset, int length) OutputStream方法如下: int write(int c) int write(byte cbuf) int write(byte cbuf, int offset, int length) 4. 各种流简介 表10.1列出了java.io包中的各种流和它们的功能。注意,这些流都能传输 char和byte,两种不同的数据类型。 l表10.1 10.2 各种流的使用 10.2.1 文件流 文件流(File streams)是用来传输当前系统下的某个文件中的一些内容 的,它应该是最简单的一种流,它可以是以下几种流类的对象: FileReader,FileWriter,FileInputStream和FileOutputStream。 例10.1 使用File Reader和File writer的文件复制 这个例子就是把partnovel.txt的内容传输到target.txt中,这两个 文件都在本机的e:files中。 l程序代码 例10.2 使用InputStream和OutputStream的文件复制 l程序代码 l两个方法复制同样一段文件内容,每次读取的内容是不一样的, FileReader每次读取的是一个字符(charactor),而屏幕中显示的是这 个字符的编码(0到65 535之间的一个整数)。而FileInputStream每次读 取的是一个字节(byte),而屏幕中显示的是这个字节的编码(0255之 间的一个整数)。 10.2.2 管道流 管道流(Pipe Streams)是把一个线程的输出作为另一个线程的输 入。实现它的是PipedReader、PipedWriter、PipedInputStream 和 PipedOutputStream。 管道流(Pipe Streams)的作用 如果定义了一个类,用来实现对一组词的操作,其中的一个操作是按它 们的韵(词尾)排序,方法是先把这些词的字序逆转(reverse(),然后把逆 转 后的词排序(sort(),最后再逆转每个词(reverse(),这样就得到这些词的 韵的排序。 如果不用管道流,这个操作过程必须存储两个中间过程,即经过第一 次reverse()后得到的词表和经过sort()之后的词表。如图所示 ReverseReverse Sort List of Words List of Reversed Words List of Reversed Sorted Words List of Rhyming Words 而如果用管道流,把一个方法的输出作为另一个方法的输入,就不需 要中间的存储文件了,当然这时必须用多个线程同时运行,即 revers(),sort()和reverse()一起工作,并且把中间的存储文件用 管道流来代替。如图所示。 List of Words List of Rhyming Words ReverseReverseSort 例10.3 对词汇的韵排序 这个例子中一共定义了3个类,主要的流程结构定义在RhymingWords类 中,它是这个程序的主类,另外,我们还定义了ReverseThread和 SortThread两个线程,它们的工作就是分别执行上图中指出的reverse和 sort的动作, (1)ReverseThread的作用是执行将单词的字母顺序逆转过来的 动作,源代码如下: l程序代码 l这个线程对读入的每一行数据调用了reverseIt()方法,并将逆 转完毕的单词输出到一个OutputStream类对象中去。注意,在 这段程序中,我们只使用了普通的输入输出流。 (2) SortThread的作用是对单词进行排序,其源代码如下: l程序代码 (3)RhymingWords类控制着整个程序的流程: l程序代码 对于管道流的使用主要体现在粗体的代码段,如reverse()方法中的 语句: PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut); l以上的两句作用是建立一个管道,管道的一头是PipedWriter,另一头 是PipedReader,并且,任何从PipedWriter写入的内容都可以从 PipedReader读出。形成这个管道的过程就是在一个PipedReader上建 立一个PipedWriter。管道流和文件流的主要区别是文件流必须建立在 一个文件上,而管道流是在两个线程之间建立管道,而不是建立在某 个文件或线程上。所以,管道流的建立过程是先创建一个空的 PipedWriter,然后在PipedWriter上创建PioedReader。程序运行时 Reverse线程把内容输入到管道的PipedWriter端,Sort线程从管道的 PipedReader端读出如图所示。sort()方法中的管道流同样,只是使用管 道的线程不同而已。PipedwriterPipedReaberReversebortThe Pipe l管道的连接Pipedwriter PipedReaber Reverse bort The Pipe 快排序的算法 /这是一个快排序的方法,它的思路是先设一个中间点,然后通过左右对调 /把值小于中间点的元素放到中间点的左边,值大于中间点的元素放到右边 /然后对左右两部分重复以上算法,直到完成排序,所以这是一个递归算法 假设Words.txt文件中的内容如下: in new BufferedWriter source Pipe pipeOut PipedWriter hi flower airplane computer networks top pcgamenew l程序代码 输出结果如图所示 10.2.3 连接文件 如果需要读取多个文件,并把它们连接在一起,就需要流类 SequenceInputStream。 例10.4 用一个流读取多个文件并连接 l程序首先创建一个ListOfFiles类的对象myList来存放命令行 输入的多个文件名,然后创建一个SequenceInputStream对象 ,它将按myList指示的顺序读取多个文件并将它们连接。 l程序代码 10.2.4 过滤流 java.io包中提供了一个类族,这些类实现过滤输入输出,这些类的根类 是FilterInputStream和FilterOutputStream,它们是抽象类。当使用过滤 流时,比一般流多一道工序,就是过滤。过滤流是建筑在其他流之上的, 如过滤流的方法read()从下层流中读取数据,并过滤后传给程序,而 write()方法是先过滤后,再把数据写入下层流。 FilterInputStream和FilterOutputStream的子类如下: DataInputStream 和 DataOutputStream BufferedInputStream 和 BufferedOutputStream LineNumberInputStream PushbackInputStream PrintStream 1. 使用过滤流 要使用过滤流必须使它附加在其他流上,可以在一个标准的输 入 流上附加一个过滤输入流,例如: BufferedReader d = new BufferedReader(new DataInputStream(System.in); String input; while (input = d.readLine() != null) 例10.5 使用DataInputStream和DataOutputStream进行过滤输入 输出 这个程序的结构是,首先给出一系列数据,然后把这些数据通 过 过滤流输出到一个文件中,最后再从文件中读到屏幕上。 l程序代码 2. 定义自己的过滤流 许多时候我们需要特殊的过滤方式,而在Java类库中没有所需 的 过滤流,这时就必须自己定义。定义自己的过滤流应注意以下几 点: l过滤流应该是DataInputStream和DataOutputStream的子类,而且经过 过滤的数据其他方法不能读出。一般情况下,输入和输出是成对出现 的,所以一次定义两个流(输入、输出)。 l如果需要,重载read()和write()。 l可以定义其他的特殊方法完成过滤。 l确保输入和输出流一起工作。 例10.6 创建自己的过滤流 l这个例子的名字为CheckSum,其作用是判断从输入流中读入的数 据是否与从输出流中写入的数据相符,通过这个程序,可以实现在 IO方面的多种检查算法,以保证输入流与输出流之间的一致,类似 的程序在网络管理软件中经常会用到。 l这个例子一共定义了4个类和一个接口,它们分别是: 过滤流的两个子类:CheckedOutputStream和CheckedInputStream。 CheckSum 接口以及实现这个接口的类Adler32。 CheckedIODemo 类用于为这个程序定义main函数。 (1)CheckedOutputStream类的源代码如下: l程序代码 在这个类中,请注意以下几点: l首先继承了FilterOutputStream类,这是自定义过滤流必要的第一步 。 l然后定义了它的构造器,这个类的构造器只有一个,其使用的参数包 括一个OutputStream类变量,这个变量即为该过滤流要过滤的输出流 ,另外一个参数是这个过滤流的私有变量,它是CheckSum类型的,其 作用是用来更新程序的检 查和。 lFilterOutputStream中定义了3个不同的write()方法,这里 CheckedOutputStream将这3个方法都做了重载,每次调用write()方法 时,它都先写入数据,然后进行检查并更新检查和。 (2)CheckedInputStream类的源代码如下: l程序代码 l这个类与上面的CheckedOutputStream基本上是类似的,它继承了 FilterInputStream,其构造器也只有一个,其中的参数是需要过滤的输 入流和一个CheckSum类的私有变量,用来标识检查和,并且也将 FilterInputStream的3个read()方法都进行了重载,重载的方法就是先 读入数据,再进行检查。 (3)CheckSum接口的源代码如下: interface Checksum public void update(int b); public void update(byte b, int off, int len); public long getValue(); public void reset(); 下面的类来具体实现了检查动作。 (4)Adler32类的源代码如下: l程序代码 这个类使用了CRC-32(循环冗余)算法对输入、输出流进行检查,我们不 用关心这段程序每个方法内部程序是什么意思,只要注意一下,Adler32 类 实现了CheckSum接口的所有方法就可以了。 (5)CheckedIODemo类的源代码 除了上面介绍的几个类和接口之外,还有这样一些程序段,其作 用 是控制整个程序的流程,源代码如下: l程序代码 假设farrago.txt文件中存有下面一些内容: So she went into the garden to cut a cabbage-leaf, to make an apple-pie; and at the same time a great she-bear, coming up the street, pops its head into the shop. What! no soap? So he died, and she very imprudently married the barber; and there were present the Picninnies, and the Joblillies, and the Garyalies, and the grand Panjandrum himself, with the little round button at top, and they all fell to playing the game of catch as catch can, till the gun powder ran out at the heels of their boots. Samuel Foote 1720-1777 我们将得到如下运行结果: Input stream check sum: 736868089 Output stream check sum: 736868089 10.2.5 对象的序列化 1. 序列化对象 ObjectInputStream和ObjectOutputStream必须建筑在其他流类的基础 上,这和过滤流相似。如果把一个对象看做一个活动房屋, ObjectOutputStream和ObjectInputStream就是把房屋拆散和重新组装, 当 然这个过程是有一定顺序的,而其他的流类就负责零件的运输。我们先看 ObjectOutputStream,这是拆的过程。 例10.7 对象序列化 l程序代码 l这个例子中的ObjectOutputStream和ObjectInputStream都是建立在 FileOutputStream和FileInputStream之上的(粗体部分),然后通过sOut 和sIn的方法writeObject()和readObject()来输入和输出对象,这里被传 输的对象是字符串“thetime:”和Date类实例。 lObjectOutputStream实现了接口DataOutput,这个接口定义了许多输出 简单数据的方法,如writeInt(),writeFloat()和writeUTF等,读者可以 用这些方法直接把简单数据写入ObjectOutputStream。与之对应 ObjectInputStream有多个读入简单数据的方法,如readInt(), readFloat()等等。 2. 定义能序列化的类 一个类只有实现了接口Serializable,它的对象才能被序列化。这听起 来很麻烦,事实上,Serializable接口是个空接口,它不含有任何方法, 下面就是这个接口的定义: package java.io; public interface Serializable ; /很幸运,括号内没有任何东西 这样我们要使某个类的对象可被序列化,只需要在这个类的类头声明实 现接口Serializable,而它的其他定义不用进行丝毫改动,例如: public class MySerializableClass implements Serializable 如何对对象进行序列化一般不需要编程者自己定义 ldefaultWriteObject()方法来处理这件事 ldefaultReadObject()方法类重组对象 这两个方法分别被writeObject()和readObject()及其他方法调用。默认的序列化 方法比较慢。 如果需要还是可以在序列化之后进行其他操作,这就要重载 writeObject()和readObject()。但调用默认的序列化方法必须放在 第一句,如同下面的格式: private void writeObject(ObjectOutputStream s) throws IOException s.defaultWriteObject(); /自定义部分 private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException s.defaultReadObject(); /自定义部分 10.2.6 随机访问 首先我们看一下为什么需要随机访问。假如有一个ZIP文档,大 家知道这是一个压缩文档,里面可能包含多个文件,在ZIP文档的 最后由各个文件的索引。它的结构如图10.11所示。 file info file file contentsdir-entry 当我们需要取出其中的一个文件时,如果用顺序访问必须经过下面4 个步骤: (1)打开ZIP文档。 (2)顺序查找这个文档,直到找到所需要的文件。 (3)解压缩这个文件。 (4)关闭ZIP文档。 可以看出,如果用这种算法,当找到所需文件时平均需要读取半个文 档,所以这个算法的效率是很低的。但如果用随机访问方法就不会这样, 我们只需找到文档最后的索引,然后根据索引找到文件的位置,直接解压 缩文件,然后关闭ZIP文档。 lRandomAccessFile类和前面的输入输出流不同,它把输入输出放到一 个类中,通过其不同的构造函数来确定是输出还是输入。并且它是一 个独立分支的类,并不是InputStream或OutputStream的衍生类 lRandomAccessFile类可以随机访问本机的某个文件,只要必须提供这 个文件的名称或代表这个文件的File类对象,这点和FileInputStream、 FileOutputStream相似。下面是创建随机访问的实例,构造函数中的第 二个参数只有“r”(只读)或“rw”(可读写)。 new RandomAccessFile(“partnovel.txt“, “r“); /创建一个对文件partnovel的 只读随机访问 new RandomAccessFile(“farrago.txt“, “rw“); /创建一个对文件farrago的可 读写随机访问 一旦建立了对文件的随机访问,就可以使用read()和write()方法了

温馨提示

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

评论

0/150

提交评论