第 8 章 输入输出流 i/o

46
8 8 第 第第第第第 第 第第第第第 I/O I/O

Upload: eric-hensley

Post on 03-Jan-2016

164 views

Category:

Documents


13 download

DESCRIPTION

第 8 章 输入输出流 I/O. 一、输入输出流 I/O 是计算机的最基本操作。. 比如从键盘输入数据、从文件中读取数据或向文件中写数据、通过网络上传或下载数据等。 Java 类库的设计者是通过创建大量的类来解决这个难题的。 在 java 中有关流的操作使用 io 包 import java.io.*;. 在 JDK1.4 中,添加了 nio 类,用于改进性能及功能。 我们需要学习相当数量的类。另外,很有必要理解 I/O 类库的演化过程, 本章就介绍 Java 标准类库中各种各样的类以及它们的用法。. 流式 I/O. - PowerPoint PPT Presentation

TRANSCRIPT

第第 88 章 输入输出流章 输入输出流 I/OI/O

一、输入输出流一、输入输出流 I/OI/O 是计算机的最基本操作。是计算机的最基本操作。

比如从键盘输入数据、从文件中读取比如从键盘输入数据、从文件中读取数据或向文件中写数据、通过网络上数据或向文件中写数据、通过网络上传或下载数据等。传或下载数据等。

JavaJava 类库的设计者是通过创建大量的类库的设计者是通过创建大量的类来解决这个难题的。类来解决这个难题的。

在在 javajava 中有关流的操作使用 中有关流的操作使用 io io 包包 import java.io.*;import java.io.*;

在 JDK1.4 中,添加了 nio 类,用于改进性能及功能。

我们需要学习相当数量的类。另外,很有必要理解 I/O 类库的演化过程,

本章就介绍 Java 标准类库中各种各样的类以及它们的用法。

流式流式 I/OI/O

““ 流(流( streamstream )”是个抽象概念,它)”是个抽象概念,它代表任何有能力产出数据的数据源对象或代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。者是有能力接收数据的接收端对象。

就流的运行方向来说,有两种基本的流是:就流的运行方向来说,有两种基本的流是:输入流输入流 (Input Stream)(Input Stream) 和输出流和输出流(Output Stream)(Output Stream) 。可从中读出一系列。可从中读出一系列字节的对象称为字节的对象称为输入流输入流。而能向其中写入。而能向其中写入一系列字节的对象称为一系列字节的对象称为输出流输出流。。

按处理数据的类型不同,流的分类按处理数据的类型不同,流的分类

流 字节流

字符流

字符流适用于 16 位的字符文件每次读写 16 位字符效率较高

字节流适用于各类文件每次读写 8 位字节效率较低

Java.ioJava.io 中的四个类:中的四个类: 以字节为对象:以字节为对象: 输入流:输入流: InputStream InputStream 输出流:输出流: OutputStreamOutputStream

以字符为对象:以字符为对象: 输入流: 输入流: ReaderReader 输出流: 输出流: WriterWriter

文件处理:文件处理: FileFile 类 类 在学习那些真正用于在流中读写数据的类

之前,让我们先看看一个实用工具,它提供了一个用于帮助我们处理文件目录事务的类库。

File( 文件 ) 类。它既能代表一个特定文件的名称又能代表一个目录下的文件集合的名称。如果它指的是一个文件集,我们就可以对此集合调用 list ()方法,这个方法会返回一个字符数组。

实际上,“文件路径”对这个类来说是个更好的名字。

(( 11 )目录的检查及创建 )目录的检查及创建

文件类不仅仅只表示存在的文件或目文件类不仅仅只表示存在的文件或目录。录。

我们也可以用文件对象来创建新的目我们也可以用文件对象来创建新的目录或不存在的整个目录路径。录或不存在的整个目录路径。

我们还可以查看文件的特性(如:大我们还可以查看文件的特性(如:大小,最后修改日期,读小,最后修改日期,读 // 写),来检查写),来检查某个文件对象代表的是一个文件还是某个文件对象代表的是一个文件还是一个目录,并可以删除这个文件。一个目录,并可以删除这个文件。

(( 22 )目录列表器)目录列表器 假设我们想查看一个目录列表,可以用两

种方法列出文件对象。 (1) 如果我们调用不带参数的 list ()方法,

便可以获得此文件对象包含的全部列表。 (2) 然而,如果我们想获得一个受限列表

——例如,想得到所有扩展名为 .java 的文件——那么我们就要用到“目录过滤器”,这个类会告诉我们怎样显示符合条件的文件对象。

可以在可以在 JDKJDK 文档里的类层次结构中查文档里的类层次结构中查看到。看到。

通过继承,任何通过继承,任何 InputstreamInputstream 或或ReaderReader 衍生而来的类都含有名为衍生而来的类都含有名为readread ()的基本方法,用于读取单个()的基本方法,用于读取单个字节或者字节数组。字节或者字节数组。

同样地,任何自同样地,任何自 OutputStreamOutputStream 或或WriterWriter 衍生而来的类都含有名为衍生而来的类都含有名为writewrite ()的基本方法,用于写单个()的基本方法,用于写单个字节或者字节数组。字节或者字节数组。

InputStreamInputStream 三个基本的读方法三个基本的读方法 abstract int abstract int readread() () ::读取一个字节数据,读取一个字节数据,

并返回读到的数据,如果返回并返回读到的数据,如果返回 -1-1 ,表示读到了输,表示读到了输入流的末尾。入流的末尾。

int int readread(byte[] b) (byte[] b) ::将数据读入一个字节数将数据读入一个字节数组,同时返回实际读取的字节数。如果返回组,同时返回实际读取的字节数。如果返回 -1-1 ,,表示读到了输入流的末尾。表示读到了输入流的末尾。

int int readread(byte[] b, int off, int len) (byte[] b, int off, int len) ::将数将数据读入一个字节数组,同时返回实际读取的字节据读入一个字节数组,同时返回实际读取的字节数。如果返回数。如果返回 -1-1 ,表示读到了输入流的末,表示读到了输入流的末尾。尾。 offoff 指定在数组指定在数组 bb 中存放数据的起始偏移位中存放数据的起始偏移位置;置; lenlen 指定读取的最大字节数。指定读取的最大字节数。

其它方法其它方法 long long skipskip(long n) (long n) ::在输入流中跳过在输入流中跳过 nn 个字个字

节,并返回实际跳过的字节数。节,并返回实际跳过的字节数。 void void closeclose() () ::关闭输入流,释放和这个流相关闭输入流,释放和这个流相

关的系统资源。关的系统资源。 void void markmark(int readlimit) (int readlimit) ::在输入流的当在输入流的当

前位置放置一个标记,如果读取的字节数多于前位置放置一个标记,如果读取的字节数多于readlimitreadlimit 设置的值,则流忽略这个标记。设置的值,则流忽略这个标记。

void void resetreset() () ::返回到上一个标记。返回到上一个标记。

java.iojava.io 包中 包中 InputStreamInputStream的类层次的类层次

InputStream

FileInputStream

ByteArrayInputStream

FilterInputStream

ObjectInputStream

PipedInputStream

DataInputStream

BufferedInputStream

OutputStreamOutputStream

三个基本的写方法三个基本的写方法 abstract void abstract void writewrite(int b) (int b) ::往输出流中写入一个字节。往输出流中写入一个字节。 void void writewrite(byte[] b) (byte[] b) ::往输出流中写入数组往输出流中写入数组 bb 中的所有中的所有

字节。字节。 void void writewrite(byte[] b, int off, int len) (byte[] b, int off, int len) ::往输出流中写入往输出流中写入

数组数组 bb 中从偏移量中从偏移量 offoff开始的开始的 lenlen 个字节的数据。个字节的数据。 其它方法其它方法 void void flushflush() () ::刷新输出流,强制缓冲区中的输出字节被刷新输出流,强制缓冲区中的输出字节被

写出。写出。 void void closeclose() () ::关闭输出流,释放和这个流相关的系统资关闭输出流,释放和这个流相关的系统资

源。源。

java.iojava.io 包中 包中 OutputStreamOutputStream 的的类层次类层次

OutputStream

FileOutputStream

ByteArrayOutputStream

FilterOutputStream

ObjectOutputStream

PipedOutputStream

DataOutputStream

BufferedOutputStream

文件流文件流 FileInputStreamFileInputStream (字节文件输入(字节文件输入

流)流) FileOutputStream FileOutputStream 字节文字节文件输出流)件输出流)

节点流,用于从文件中读取或往文节点流,用于从文件中读取或往文件中写入字节流。件中写入字节流。

二进制文件的处理二进制文件的处理 文件对象的建立文件对象的建立 File fp=new File(“file1.dat”);File fp=new File(“file1.dat”); FileInputStreamFileInputStream 类:可以用它类:可以用它

来从文件中读取字节。来从文件中读取字节。 FileOutputStreamFileOutputStream 类:创建一类:创建一

个可用来将字节写入文件的输出流。个可用来将字节写入文件的输出流。

FileInputStreamFileInputStream 类的常用方法类的常用方法 ::read( ):read( ): 从流中读入数据从流中读入数据close( ):close( ): 关闭流关闭流

FileOutputStreamFileOutputStream 类的常用方类的常用方法法 ::write(byte b[ ], int off, int write(byte b[ ], int off, int len ):len ): 在数组在数组 bb 中,从中,从 offoff 开始,开始,写入写入 lenlen 个字节的数据。个字节的数据。

缓冲字节流:缓冲字节流:BufferedInputStreamBufferedInputStream 和和BufferedOutputStreamBufferedOutputStream 过滤流,需要使用已经存在的过滤流,需要使用已经存在的

节点流来构造,提供带缓冲的节点流来构造,提供带缓冲的读写,提高了读写的效率。读写,提高了读写的效率。

DataInputStreamDataInputStream (数据输入(数据输入流)流) DataOutputStreamDataOutputStream (数(数据输出流 )据输出流 )

过滤流,需要使用已经存在的节点过滤流,需要使用已经存在的节点流来构造,提供了读写流来构造,提供了读写 JavaJava 中的中的基本数据类型的功能。基本数据类型的功能。

PipedInputStreamPipedInputStream 和和PipedOutputStreamPipedOutputStream

管道流,用于线程间的通信。一管道流,用于线程间的通信。一个线程的个线程的 PipedInputStreamPipedInputStream 对对象从另一个线程的象从另一个线程的PipedOutputStreamPipedOutputStream 对象读取对象读取输入。要使管道流有用,必须同时输入。要使管道流有用,必须同时构造管道输入流和管道输出流。构造管道输入流和管道输出流。

Java I/OJava I/O 库的设计原则库的设计原则 JavaJava 的的 I/OI/O 库提供了一个称做链接的机制,库提供了一个称做链接的机制,

可以将一个流与另一个流首尾相接,形成可以将一个流与另一个流首尾相接,形成一个流管道的链接。通过流的链接,可以一个流管道的链接。通过流的链接,可以动态的增加流的功能,而这种功能的增加动态的增加流的功能,而这种功能的增加是通过组合一些流的基本功能而动态获取是通过组合一些流的基本功能而动态获取的。的。

I/OI/O 流的链接流的链接

FileInputStreamBufferedInputStreamDataInputStream数据

DataOutputStreamBufferedOutputStreamFileOutputStream数据

从文件中获取输入字节 增加了缓冲的功能增加了读取 Java 基本数据类型的功能

Input Stream Chain

Output Stream Chain

可以往输出流中写入Java 基本数据类型

提供数据写入到缓冲区的功能 将数据写入到文件中

ReaderReader 和和 WriterWriter

JavaJava 程序语言使用程序语言使用 UnicodeUnicode 来表来表示字符串和字符。示字符串和字符。

ReaderReader 和和 WriterWriter 这两个抽象类这两个抽象类主要用来读写字符流。主要用来读写字符流。

字节流不能直接操作字节流不能直接操作 UnicodeUnicode 字字符,所以符,所以 JavaJava 提供了字符流。提供了字符流。

由于汉字在文件中占两个字节,如由于汉字在文件中占两个字节,如果使用字节流,读取不当会出现乱果使用字节流,读取不当会出现乱码现象,采用字符流就可以避免这码现象,采用字符流就可以避免这个现象,因为,在个现象,因为,在 UnicodeUnicode 字符字符中,一个汉字被看作一个字符。中,一个汉字被看作一个字符。

java.iojava.io 包中包中 ReaderReader 的类层次的类层次

Reader

BufferedReader

CharArrayReader

FilterReader

PipedReader

StringReader

FileReader

LineNumberReader

PushbackReader

InputStreamReader

java.iojava.io 包中包中 WriterWriter 的类层次的类层次

Writer

BufferedWriter

CharArrayWriter

FilterWriter

PipedWriter

PrintWriter

FileWriter OutputStreamWriter

StringWriter

操作字符文件的类操作字符文件的类 FileReader FileReader 读取文件;读取文件; FileWriter FileWriter 写入文件;写入文件; BufferedReader BufferedReader 输入到缓冲区。输入到缓冲区。 BufferedWriter BufferedWriter 输出到缓冲区。输出到缓冲区。

字符流的读写操作方法字符流的读写操作方法

从输入流中按行读取字符的方法:从输入流中按行读取字符的方法: String readLine()String readLine() ;; 向输出流写入多个字符的方法:向输出流写入多个字符的方法: write(String s, int off, int len)write(String s, int off, int len) ;; 将指定的字符串将指定的字符串 ss 从偏移量 从偏移量 off off 开始的 开始的

len len 个字符写入文件输出流。个字符写入文件输出流。

标准标准 I/OI/O 重定向重定向 JavaJava 的的 SystemSystem 类提供一些简单的静态方法调用,类提供一些简单的静态方法调用,允许我们对标准输入、输出和错误允许我们对标准输入、输出和错误 I/OI/O 流进行流进行重重定向定向: :

setIn(InputStream) setIn(InputStream) :将标准输入重定向到:将标准输入重定向到InputStreamInputStream 的对象。的对象。

setOut(PrintStream) setOut(PrintStream) setErr(PrintStream) setErr(PrintStream) 如果我们突然开始在显示器上创建大量输出,而如果我们突然开始在显示器上创建大量输出,而

这些输出滚动的如此之快以至于无法阅读时,重这些输出滚动的如此之快以至于无法阅读时,重定向输出就显得极为有用。定向输出就显得极为有用。

对于“我们想重复测试特定用户的输入序列”的对于“我们想重复测试特定用户的输入序列”的命令行程序来说,重定向输入就很有价值。命令行程序来说,重定向输入就很有价值。

下例简单演示了这些方法的使用: 下例简单演示了这些方法的使用:

这个程序将标准输入附加在文件上,并将标准输出和标准错误重定向到另一个文件。I/O重定向操纵的是字节流,而不是字符流,因此我们使用的是 InputStream 和 OutputStream 而不是 Reader 和 Writer 。

随机存取文件流随机存取文件流RandomAccessFileRandomAccessFile

前面学习的文件流都是按顺序访问的,文前面学习的文件流都是按顺序访问的,文件操作中经常要用到随机访问。随机存取件操作中经常要用到随机访问。随机存取文件流文件流 RandomAccessFileRandomAccessFile 类可以读写类可以读写文件中任意位置上的字节、文本等数据。文件中任意位置上的字节、文本等数据。

RandomAccessFileRandomAccessFile 并不是并不是InputStreamInputStream 、、 OutputStreamOutputStream 、、 ReaReaderder 或或 WriterWriter 的子类,因为它既可以输入,的子类,因为它既可以输入,又可以输出,并且既可以操作字符,又可又可以输出,并且既可以操作字符,又可以操作字节。该类的构造器有一个参数,以操作字节。该类的构造器有一个参数,用来声明所构建的流是用于输入还是用于用来声明所构建的流是用于输入还是用于输出,或者既用于输入,又用于输出。输出,或者既用于输入,又用于输出。

随机存取文件流随机存取文件流RandomAccessFileRandomAccessFile

RandomAccessFileRandomAccessFile 类同时实现了类同时实现了DataInputDataInput 和和 DataOutputDataOutput 接口,提供了接口,提供了对文件随机存取的功能,利用这个类可以对文件随机存取的功能,利用这个类可以在文件的任何位置读取或写入数据。在文件的任何位置读取或写入数据。

读取和写入集中到一个类中。读取和写入集中到一个类中。

RandomAccessFileRandomAccessFile 类提供了一个文件指类提供了一个文件指针,用来标志要进行读写操作的下一数据针,用来标志要进行读写操作的下一数据的位置。的位置。

Seek(long a):Seek(long a): 用来定位流的读写位置,用来定位流的读写位置,其中参数其中参数 aa 确定读写位置距离文件开头的确定读写位置距离文件开头的字节个数。字节个数。

getFilePointer( )getFilePointer( ) 获取流的当前位置。获取流的当前位置。 RandomAccessFileRandomAccessFile 流对文件的读写比顺流对文件的读写比顺序读写更为灵活。序读写更为灵活。

对象序列化对象序列化 将对象转换为字节流保存起来,并在日后将对象转换为字节流保存起来,并在日后

还原这个对象,这种机制叫做对象序列化。还原这个对象,这种机制叫做对象序列化。 对象序列化就是把一个对象的状态记录下对象序列化就是把一个对象的状态记录下

来。来。 一个对象要想能够实现序列化,必须实现一个对象要想能够实现序列化,必须实现

SerializableSerializable 接口。接口。

对象流对象流 ObjectInputStreamObjectInputStream 类创建的对象被称类创建的对象被称

为对象输入流为对象输入流 ObjectOutputStreamObjectOutputStream 类创建的对象被称类创建的对象被称

为对象输出流为对象输出流 ObjectInputStreamObjectInputStream 类和类和

ObjectOutputStreamObjectOutputStream 类分别是类分别是InputStreamInputStream 类和类和 OutputStreamOutputStream 类的类的子类。子类。

对象输出流使用对象输出流使用 writeObject(Object writeObject(Object obj)obj) 方法将一个对象方法将一个对象 objobj 写入输出流送往写入输出流送往目的地目的地

对象输入流使用对象输入流使用 readObject()readObject() 方法从源中方法从源中读取一个对象到程序中。读取一个对象到程序中。

当使用对象流写入或读入对象时,要保证当使用对象流写入或读入对象时,要保证对象是序列化的。这是为了保证能把对象对象是序列化的。这是为了保证能把对象写入到文件,并能再把对象正确读回到程写入到文件,并能再把对象正确读回到程序中的缘故。序中的缘故。

一个类如果实现了一个类如果实现了 SerializableSerializable 接口,那接口,那么这个类创建的对象就是所谓序列化的对么这个类创建的对象就是所谓序列化的对象。象。

SerializableSerializable 接口中的方法对程序是不可接口中的方法对程序是不可见的,因此,实现该接口的类不需要实现见的,因此,实现该接口的类不需要实现额外的方法,当把一个序列化的对象写入额外的方法,当把一个序列化的对象写入到对象输出流时,到对象输出流时, JVMJVM 就会实现就会实现SerializableSerializable 接口中的方法,将一定格式接口中的方法,将一定格式的文本的文本 ------------ 对象的序列化信息,写入到目对象的序列化信息,写入到目的地。的地。

在在 SunSun公司的公司的 jdkjdk 自带的自带的 rt.jar rt.jar 包文件中,有包文件中,有AudioStream.classAudioStream.class 、、 AudioPlayer.classAudioPlayer.class 类用类用于于播放声音文件,我们可以使用输入流:播放声音文件,我们可以使用输入流:

FileInputStream file=new FileInputStream file=new FileInputStream("FileInputStream("声音文件声音文件 .wav");.wav");

AudioStream audio=new AudioStream audio=new AudioStream(file);AudioStream(file);

使用使用 AudioPlayerAudioPlayer 类的类的 start()start() 进行播放:进行播放: AudioPlayer.player.start(audio);AudioPlayer.player.start(audio);

【【例例 8-138-13】】应用输入流播放音频文件。应用输入流播放音频文件。

8.5 Java8.5 Java 多媒体技术多媒体技术

8.5.28.5.2 JavaJava 多媒体包多媒体包 JMFJMF 的应的应用用

JavaJava 有一个多媒体包有一个多媒体包 JMFJMF (( Java Media Java Media FrameworkFramework ),可以用来编写多媒体应用程序。),可以用来编写多媒体应用程序。建立一个多媒体程序有下列几个步骤:建立一个多媒体程序有下列几个步骤:11 、创建多媒体播放对象、创建多媒体播放对象

try{try{

MediaLocator mrl=new MediaLocator(MediaLocator mrl=new MediaLocator( 多媒体文多媒体文件名件名 ););

player=Manager.createPlayer(mrl);player=Manager.createPlayer(mrl);

}}

catch(MalformedURLException e){ }catch(MalformedURLException e){ }

catch(IOException e){ }catch(IOException e){ }

catch(NoPlayerException e){ }catch(NoPlayerException e){ }

22 、向多媒体播放对象注册控制监视器、向多媒体播放对象注册控制监视器player.addControllerListener(player.addControllerListener( 监视器监视器 ););

33 、让多媒体播放对象对播放媒体进行预提、让多媒体播放对象对播放媒体进行预提取取player.prefetch();player.prefetch();

44 、启动多媒体播放对象、启动多媒体播放对象player.start();player.start();

55 、停止并释放多媒体播放对象、停止并释放多媒体播放对象 player.stop();player.stop();

player.deallocate(); player.deallocate();

player.close();player.close();

【【例例 8-148-14 】】设计一个简易多媒体播放器。设计一个简易多媒体播放器。

总结总结 InputStreamInputStream 和和 OutputStreamOutputStream :字节:字节

流的输入输出。流的输入输出。 ReaderReader 和和 WriterWriter :字符流的输入输出。:字符流的输入输出。 流的链接流的链接 (Java I/O(Java I/O 库的设计原则库的设计原则 ))

本章结束本章结束