460 likes | 615 Views
第 8 章 输入输出流 I/O. 一、输入输出流 I/O 是计算机的最基本操作。. 比如从键盘输入数据、从文件中读取数据或向文件中写数据、通过网络上传或下载数据等。 Java 类库的设计者是通过创建大量的类来解决这个难题的。 在 java 中有关流的操作使用 io 包 import java.io.*;. 在 JDK1.4 中,添加了 nio 类,用于改进性能及功能。 我们需要学习相当数量的类。另外,很有必要理解 I/O 类库的演化过程, 本章就介绍 Java 标准类库中各种各样的类以及它们的用法。. 流式 I/O.
E N D
一、输入输出流I/O是计算机的最基本操作。 • 比如从键盘输入数据、从文件中读取数据或向文件中写数据、通过网络上传或下载数据等。 • Java类库的设计者是通过创建大量的类来解决这个难题的。 • 在java中有关流的操作使用 io 包 • import java.io.*;
在JDK1.4中,添加了nio类,用于改进性能及功能。在JDK1.4中,添加了nio类,用于改进性能及功能。 • 我们需要学习相当数量的类。另外,很有必要理解I/O类库的演化过程, • 本章就介绍Java标准类库中各种各样的类以及它们的用法。
流式I/O • “流(stream)”是个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。 • 就流的运行方向来说,有两种基本的流是:输入流(Input Stream)和输出流(Output Stream)。可从中读出一系列字节的对象称为输入流。而能向其中写入一系列字节的对象称为输出流。
按处理数据的类型不同,流的分类 字节流 • 流 字符流 • 字符流 • 适用于16位的字符文件 • 每次读写16位字符 • 效率较高 字节流 适用于各类文件 每次读写8位字节 效率较低
Java.io中的四个类: • 以字节为对象: • 输入流:InputStream • 输出流:OutputStream • 以字符为对象: • 输入流: Reader • 输出流: Writer
文件处理:File类 • 在学习那些真正用于在流中读写数据的类之前,让我们先看看一个实用工具,它提供了一个用于帮助我们处理文件目录事务的类库。 • File(文件)类。它既能代表一个特定文件的名称又能代表一个目录下的文件集合的名称。如果它指的是一个文件集,我们就可以对此集合调用list()方法,这个方法会返回一个字符数组。 • 实际上,“文件路径”对这个类来说是个更好的名字。
(1)目录的检查及创建 • 文件类不仅仅只表示存在的文件或目录。 • 我们也可以用文件对象来创建新的目录或不存在的整个目录路径。 • 我们还可以查看文件的特性(如:大小,最后修改日期,读/写),来检查某个文件对象代表的是一个文件还是一个目录,并可以删除这个文件。
(2)目录列表器 • 假设我们想查看一个目录列表,可以用两种方法列出文件对象。 • (1)如果我们调用不带参数的list()方法,便可以获得此文件对象包含的全部列表。 • (2)然而,如果我们想获得一个受限列表——例如,想得到所有扩展名为.java的文件——那么我们就要用到“目录过滤器”,这个类会告诉我们怎样显示符合条件的文件对象。
可以在JDK文档里的类层次结构中查看到。 • 通过继承,任何Inputstream或Reader衍生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。 • 同样地,任何自OutputStream或Writer衍生而来的类都含有名为write()的基本方法,用于写单个字节或者字节数组。
InputStream • 三个基本的读方法 abstract int read() :读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。 int read(byte[]b) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。 int read(byte[]b, intoff, intlen) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。
其它方法 long skip(longn) :在输入流中跳过n个字节,并返回实际跳过的字节数。 void close() :关闭输入流,释放和这个流相关的系统资源。 void mark(intreadlimit) :在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。 void reset() :返回到上一个标记。
java.io包中 InputStream的类层次 FileInputStream ByteArrayInputStream DataInputStream InputStream FilterInputStream BufferedInputStream ObjectInputStream PipedInputStream
OutputStream • 三个基本的写方法 abstract void write(intb) :往输出流中写入一个字节。 void write(byte[]b) :往输出流中写入数组b中的所有字节。 void write(byte[]b, intoff, intlen) :往输出流中写入数组b中从偏移量off开始的len个字节的数据。 • 其它方法 void flush() :刷新输出流,强制缓冲区中的输出字节被写出。 void close() :关闭输出流,释放和这个流相关的系统资源。
java.io包中 OutputStream的类层次 FileOutputStream ByteArrayOutputStream DataOutputStream FilterOutputStream OutputStream ObjectOutputStream BufferedOutputStream PipedOutputStream
文件流 • FileInputStream(字节文件输入流)FileOutputStream 字节文件输出流) 节点流,用于从文件中读取或往文件中写入字节流。
二进制文件的处理 • 文件对象的建立 • File fp=new File(“file1.dat”); • FileInputStream类:可以用它来从文件中读取字节。 • FileOutputStream类:创建一个可用来将字节写入文件的输出流。
FileInputStream类的常用方法: • read( ):从流中读入数据 • close( ):关闭流 • FileOutputStream类的常用方法: • write(byte b[ ], int off, int len ):在数组b中,从off开始,写入len个字节的数据。
缓冲字节流:BufferedInputStream和BufferedOutputStream • 过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率。
DataInputStream(数据输入流)DataOutputStream(数据输出流 ) • 过滤流,需要使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能。
PipedInputStream和PipedOutputStream 管道流,用于线程间的通信。一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。要使管道流有用,必须同时构造管道输入流和管道输出流。
Java I/O库的设计原则 • Java的I/O库提供了一个称做链接的机制,可以将一个流与另一个流首尾相接,形成一个流管道的链接。通过流的链接,可以动态的增加流的功能,而这种功能的增加是通过组合一些流的基本功能而动态获取的。
I/O流的链接 Input Stream Chain 增加了读取Java基本数据类型的功能 从文件中获取输入字节 增加了缓冲的功能 BufferedInputStream 数据 FileInputStream DataInputStream Output Stream Chain 提供数据写入到缓冲区的功能 可以往输出流中写入Java基本数据类型 将数据写入到文件中 BufferedOutputStream 数据 DataOutputStream FileOutputStream
Reader和Writer • Java程序语言使用Unicode来表示字符串和字符。 • Reader和Writer这两个抽象类主要用来读写字符流。 • 字节流不能直接操作Unicode字符,所以Java提供了字符流。
由于汉字在文件中占两个字节,如果使用字节流,读取不当会出现乱码现象,采用字符流就可以避免这个现象,因为,在Unicode字符中,一个汉字被看作一个字符。由于汉字在文件中占两个字节,如果使用字节流,读取不当会出现乱码现象,采用字符流就可以避免这个现象,因为,在Unicode字符中,一个汉字被看作一个字符。
java.io包中Reader的类层次 BufferedReader LineNumberReader CharArrayReader Reader FilterReader PushbackReader InputStreamReader FileReader PipedReader StringReader
java.io包中Writer的类层次 BufferedWriter CharArrayWriter Writer FilterWriter OutputStreamWriter FileWriter PipedWriter PrintWriter StringWriter
操作字符文件的类 • FileReader 读取文件; • FileWriter 写入文件; • BufferedReader 输入到缓冲区。 • BufferedWriter 输出到缓冲区。
字符流的读写操作方法 从输入流中按行读取字符的方法: String readLine(); • 向输出流写入多个字符的方法: write(Strings, intoff, intlen); 将指定的字符串s从偏移量 off 开始的 len 个字符写入文件输出流。
标准I/O重定向 • Java的System类提供一些简单的静态方法调用,允许我们对标准输入、输出和错误I/O流进行重定向: • setIn(InputStream) :将标准输入重定向到InputStream的对象。 • setOut(PrintStream) • setErr(PrintStream) • 如果我们突然开始在显示器上创建大量输出,而这些输出滚动的如此之快以至于无法阅读时,重定向输出就显得极为有用。 • 对于“我们想重复测试特定用户的输入序列”的命令行程序来说,重定向输入就很有价值。 • 下例简单演示了这些方法的使用:
这个程序将标准输入附加在文件上,并将标准输出和标准错误重定向到另一个文件。这个程序将标准输入附加在文件上,并将标准输出和标准错误重定向到另一个文件。 I/O重定向操纵的是字节流,而不是字符流,因此我们使用的是InputStream 和OutputStream而不是Reader和Writer。
随机存取文件流RandomAccessFile • 前面学习的文件流都是按顺序访问的,文件操作中经常要用到随机访问。随机存取文件流RandomAccessFile类可以读写文件中任意位置上的字节、文本等数据。
RandomAccessFile并不是InputStream、OutputStream、Reader或Writer的子类,因为它既可以输入,又可以输出,并且既可以操作字符,又可以操作字节。该类的构造器有一个参数,用来声明所构建的流是用于输入还是用于输出,或者既用于输入,又用于输出。RandomAccessFile并不是InputStream、OutputStream、Reader或Writer的子类,因为它既可以输入,又可以输出,并且既可以操作字符,又可以操作字节。该类的构造器有一个参数,用来声明所构建的流是用于输入还是用于输出,或者既用于输入,又用于输出。
随机存取文件流RandomAccessFile • RandomAccessFile类同时实现了DataInput和DataOutput接口,提供了对文件随机存取的功能,利用这个类可以在文件的任何位置读取或写入数据。 • 读取和写入集中到一个类中。
RandomAccessFile类提供了一个文件指针,用来标志要进行读写操作的下一数据的位置。RandomAccessFile类提供了一个文件指针,用来标志要进行读写操作的下一数据的位置。 • Seek(long a):用来定位流的读写位置,其中参数a确定读写位置距离文件开头的字节个数。 • getFilePointer( )获取流的当前位置。 • RandomAccessFile流对文件的读写比顺序读写更为灵活。
对象序列化 • 将对象转换为字节流保存起来,并在日后还原这个对象,这种机制叫做对象序列化。 • 对象序列化就是把一个对象的状态记录下来。 • 一个对象要想能够实现序列化,必须实现Serializable接口。
对象流 • ObjectInputStream类创建的对象被称为对象输入流 • ObjectOutputStream类创建的对象被称为对象输出流 • ObjectInputStream类和ObjectOutputStream类分别是InputStream类和OutputStream类的子类。
对象输出流使用writeObject(Object obj)方法将一个对象obj写入输出流送往目的地 • 对象输入流使用readObject()方法从源中读取一个对象到程序中。
当使用对象流写入或读入对象时,要保证对象是序列化的。这是为了保证能把对象写入到文件,并能再把对象正确读回到程序中的缘故。当使用对象流写入或读入对象时,要保证对象是序列化的。这是为了保证能把对象写入到文件,并能再把对象正确读回到程序中的缘故。 • 一个类如果实现了Serializable接口,那么这个类创建的对象就是所谓序列化的对象。
Serializable接口中的方法对程序是不可见的,因此,实现该接口的类不需要实现额外的方法,当把一个序列化的对象写入到对象输出流时,JVM就会实现Serializable接口中的方法,将一定格式的文本------对象的序列化信息,写入到目的地。Serializable接口中的方法对程序是不可见的,因此,实现该接口的类不需要实现额外的方法,当把一个序列化的对象写入到对象输出流时,JVM就会实现Serializable接口中的方法,将一定格式的文本------对象的序列化信息,写入到目的地。
8.5 Java多媒体技术 在Sun公司的jdk自带的rt.jar 包文件中,有AudioStream.class、AudioPlayer.class类用于 播放声音文件,我们可以使用输入流: FileInputStream file=new FileInputStream("声音文件.wav"); AudioStream audio=new AudioStream(file); 使用AudioPlayer类的start()进行播放: AudioPlayer.player.start(audio); 【例8-13】应用输入流播放音频文件。
8.5.2Java多媒体包JMF的应用 • Java有一个多媒体包JMF(Java Media Framework),可以用来编写多媒体应用程序。建立一个多媒体程序有下列几个步骤: 1、创建多媒体播放对象 try{ MediaLocator mrl=new MediaLocator(多媒体文件名); player=Manager.createPlayer(mrl); } catch(MalformedURLException e){ } catch(IOException e){ } catch(NoPlayerException e){ }
2、向多媒体播放对象注册控制监视器 player.addControllerListener(监视器); • 3、让多媒体播放对象对播放媒体进行预提取 player.prefetch(); • 4、启动多媒体播放对象 player.start(); • 5、停止并释放多媒体播放对象 player.stop(); player.deallocate(); player.close();
总结 • InputStream和OutputStream:字节流的输入输出。 • Reader和Writer:字符流的输入输出。 • 流的链接(Java I/O库的设计原则)