资源描述
第7章输入/输出流,主讲教师:丁天翔,本章知识点,流的概念InputStream和OutputStream的继承结构Reader和Writer的继承结构原始流处理器和链接流(装饰流)处理器常用流的使用文件类,流(Stream)的概念,Java语言采用流的机制来实现输入/输出。所谓流,就是数据的有序排列,而流可以是从某个源(称为流源,SourceofStream)出来,到某个目的地(称为流汇,SinkofStream)去的。根据流的方向可以将流分成输入流和输出流。一个程序总是从输入流读取数据,而向输出流写出数据Java中负责I/O的类(称为流类)统一存放在java.io包中。该包又叫做I/O库,流的处理过程(输入),用来处理流的流类又称为流处理器例如,一个java程序可以使用FileInputStream类直接从一个文件中读取数据,如下图所示:,像FileInputStream这样的流类叫做流处理器。一个流处理器就像一个流的管道一样,从一个流源吸入某种类型的数据,并输出某种类型的数据。,类似地,也可以用FileOutputStream类直接向一个文件中写出数据,如下图所示:,在实际应用当中,这种简单的机制并没有太大的用处。因为程序需要写出的往往是非常结构化的信息,比如数值、文字、源代码等。这样一来,数据的转换工作将十分复杂。,流的处理过程(输出),流的处理过程(链接机制),Java的I/O库提供了一个称作链接(Chaining)的机制,可以将一个流处理器与另一个流处理器首尾相接,以其中之一的输出为输入,形成一个流管道的链接例如:DataInputStream流处理器可以把FileInputStream流对象的输出当作输入,将byte类型的数据转换成java的基本数据类型和String类型的数据,如下图所示:,节点流(原始流处理器),过滤流(链接流处理器),类似地,向一个文件写入byte类型的数据不是一个简单的过程:一个程序需要向一个文件里面写入的数据往往是结构化的,而不是byte类型的,因此在利用FileOutputStream写的时候必须首先经过转换。DataOutputStream流处理器提供了直接接收基本数据类型和String类型的方法,而这个流处理器的输出数据则是byte类型。这样一来,可以将DataOutputStream和FileOutputStream链接起来,达到直接将结构化的数据写入到文件中的目的。,int类型的数据float类型的数据String类型的数据,流的处理过程(链接机制),JavaI/O库,流处理器所处理的流必定都有流源(汇),流源(汇)分成两大类:数组、String、File等,叫原始流源。用于链接流类的流源,叫链接流源。Java语言的I/O库是对各种常见的流源、流汇、以及处理过程的抽象化,Java语言的I/O库是由一些基本的原始流处理器和围绕它们的链接流处理器所组成的,按处理数据的单位划分,Java支持两种基本的流类型:字符流和字节流,JavaI/O库的设计原则,两个对称性:输入输出对称:InputStream和OutputStream各自占据byte流的输入与输出的两个平行的类等级结构的根部;而Reader和Writer各自占据char流的输入与输出的两个平行的类等级结构的根部bytechar对称:InputStream与Reader的子类分别负责byte和char流的输入;OutputStream和Writer的子类分别负责byte和char流的输出,输入字节流InputStream,InputStream有7个直接子类,有4个属于FilterInputStream的子类注:图中深色的类是节点流处理器,其他是过滤流处理器。,原始流处理器:接收一个byte数组对象、String对象、File对象等原始流源对象,并生成一个InputStream类型的流对象。共有4个:ByteArrayInputStream:接收一个byte数组作为流源。FileInputStream:建立一个与文件有关的输入流,接收一个File对象作为流源。PipedInputStream:与PipedOutputStream配合使用,接收一个PipedOutputStream对象作为流源,可实现程序间或线程间通讯。StringBufferInputStream:(已过时)此类未能正确地将字符转换为字节。从JDK1.1开始,从字符串创建流的首选方法是通过StringReader类进行创建。,原始流处理器,链接流处理器:就是可以接收另一个流对象作为流源,并对之进行功能扩展的流类InputStream类型的链接流处理器包括以下7个,都接收另一个InputStream对象作为流源。FilterInputStream:过滤输入流,它将另一个输入流作为流源。它有4个子类:BufferedInputStream:用来从硬盘将数据读入到一个内存缓冲区中,并从该缓冲区提供数据。DataInputStream:提供基于多字节的读取方法,可以读取基本数据类型的数据。LineNumberInputStream:提供带有行计数功能的过滤输入流。PushbackInputStream:提供特殊功能,可以将已经读取的字节“推回”到输入流中。,链接流处理器(装饰流处理器),读方法intread();/从字节流对象中读入一个字节作为返回值,返回值为-1时,表示读到流的结尾。intread(byteb);/将读入的数据放在一个字节数组b中,返回所读的字节数。intread(byteb,intoff,intlen);/将读入的数据放在一个字节数组b中,返回所读的字节数。两个参数是读入数据后存放在b中的位置。流的关闭方法voidclose();/用于关闭流。其他方法intavailable();/返回输入流中还有多少可读字节。intskip(longn);/跳过流中指定字节数量的数据。,流处理器的基本方法,输出字节流OutputStream,OutputStream有5个直接子类,有3个属于FilterOutputStream的子类,原始流处理器ByteArrayOutputStream:输出流的汇集是一个byte数组FileOutputStream:输出流的汇集是一个文件对象PipedOutputStream:用于向一个数据管道输出数据,原始输出流处理器,链接流处理器:FilterOutputStream:过滤输出流,它将另一个输出流作为流汇。其子类有:BufferedOutputStream:向一个内存缓冲区中写出数据,并将此中的数据输出到硬盘中DataOutputStream:可以写出基本数据类型的数据PrintStream:用于产生格式化输出ObjectOutputStream:将基本数据类型和对象串行化,链接输出流处理器,读方法voidwrite(intb);/将指定的字节写入此输出流。write的常规协定是:向输出流写入一个字节。要写入的字节是参数b的八个低位。b的24个高位将被忽略。OutputStream的子类必须提供此方法的实现。voidwrite(byteb);/向输出流中写一个字节数组。Voidwrite(byteb,intoff,intlen);/将读入的数据放在一个字节数组b中,返回所读的字节数。两个参数是读入数据后存放在b中的位置。流的关闭方法voidclose();/当完成输入流的写操作后关闭流。其他方法Voidflush();/强制将缓存的输出数据写出到流汇。,流处理器的基本方法,如果需要对数据做真正的格式化,以便输出到像控制台显示那样,就要用PrintStream。PrintStream可以对基本数据类型和String对象组成的数据进行格式化,以形成可阅读的格式。System.out就是一个静态的PrintStream对象。PrintStream对象最重要的两个方法是print()和println()BufferedOutputStream:对一个输出流进行装饰,使得流的写出操作使用缓冲操作,提高程序效率。在涉及到物理流的地方,比如控制台I/O、文件I/O等,都应当使用这个装饰流处理器,两点说明,示例程序,从字节数组中读取数据,并在屏幕上显示读取的内容,同时将该内容写入指定的文件IODemo.txt中。读入字符串中的字符将奇数位的字母转换为大写并输出,java.lang.SystempublicfinalclassSystemextendsObjectstaticPrintStreamerr;/标准错误流(输出)staticInputStreamin;/标准输入(键盘输入流)staticPrintStreamout;/标准输出流(显示器输出流),Java的标准的数据流,注意:(1)System类不能创建对象,只能直接使用它的三个静态成员。(2)每当main方法被执行时,就自动生成上述三个对象。,System.err把错误信息送到缺省的显示(通常是显示器),System.out把输出送到缺省的显示(通常是显示器),Voidprint(参数)Voidprintln(参数),System.in从标准输入获取输入(通常是键盘)intread()/返回ASCII码。若返回值=-1,说明没有读取到任何字节读取工作结束。intread(byteb)/读入多个字节到缓冲区b中返回值是读入的字节数,importjava.io.*;classTestKeyReadpublicstaticvoidmain(Stringargs)intb;trywhile(b=System.in.read()!=-1)System.out.print(char)b);catch(IOExceptione)System.out.println(e.toString();,标准输入流System.in.read(),bytebuffer=newbyte512;System.out.println(pleaseInput:);intcount=System.in.read(buffer);System.out.println(Output:);for(inti=0;icount;i+)System.out.print(“+bufferi);System.out.println();for(inti=0;icount;i+)System.out.print(char)bufferi);Strings=newString(buffer);System.out.println(s);System.out.println(count);,标准输入流System.in.read(byteb),程序输出:,标准输入流实现中文处理,BufferedReaderstdin=newBufferedReader(newInputStreamReader(System.in);/将System.in封装到一个BufferedReader中Echo.java,字符流Reader,Reader有6个直接子类:,原始流处理器:CharArrayReader:为多线程通信提供缓冲区操作功能InputStreamReader:有一个子类FileReader,将字节流转换为字符流PipedReader:与PipedInputStream配合使用,用于读入一个数据管道里的数据StringReader:建立一个与文件有关的输入流链接流处理器:BufferedReader:从硬盘将数据读入到一个内存缓冲区,并从该缓冲区提供数据FilterReader:它将另一个输入流作为流源,字符流Reader,有7个直接子类:,字符输出流Writer,原始流处理器:CharArrayWriter:为多线程通信提供缓冲区操作功能OutputStreamWriter:建立一个与文件有关的输出流PipedWriter:与PipedOutputStream配合使用StringWriter:向一个StringBuffer写出数据链接流处理器:BufferedWriter:为Writer类型的流处理器提供缓冲区功能FilterWriter:没有子类的抽象类,将另一个输出流作为流源PrintWriter:支持格式化的文字输出,字符输出流Writer,从byte流到char流的适配,InputStreamReader是从byte流到char流的一个桥梁,它读入byte数据并根据指定的编码将之翻译成为char数据当把InputStreamReader与任何InputStream的具体子类链接时,可以从InputStream的输出读入byte类型的数据,将之转换成char类型的数据,InputStream,byte类型的数据,byte类型的数据,源,InputStreamReader,char类型的数据,汇,类似地,当与任何一个OutputStream的具体子类链接时,OutputStreamWriter可以将char类型的数据转换成为byte类型的数据,再交给输出流,OutputStreamWriter,char类型的数据,byte类型的数据,源,OutputStream,byte类型的数据,汇,从byte流到char流的适配,如何使用I/O流?,流处理器分为原始流处理器和链接流处理器。根据不同的流源,先选定合适的原始流处理器,然后用适当的链接流处理器来装饰它,最后用我们最终得到的链接流处理器对象来完成I/O操作以打开一个文件进行输入为例:为了对文件进行操作,需要使用一个FileInputStream(原始流);为了提高速度,最好先对文件进行缓冲处理,可以用一个BufferedInputStream(链接流)来装饰它;为了以格式化的形式读取输入数据,再用一个DataInputStream(链接流)来装饰它。这样,最终我们得到了一个DataInputStream对象,使用该对象来执行文件操作:DataInputStreamin=newDataInputStream(newBufferedInputStream(newFileInputStream(“Test.java”);in.readLine();,文件处理,在java.io包中,有File类提供了描述文件和目录的操作与管理方法。File不是输入/输出流类的子类,不负责数据的输入/输出,专门用来管理磁盘文件与目录。File类定义了一些与平台无关的方法进行文件操作,如建立、删除、查询、重命名等。可以用它来表示某个文件的名字,也可以用它来表示目录里一组文件的名字。创建File类文件对象File(Stringpath);/如:File(“F:/java/temp.dat”)File(Stringpath,Stringname);File(Filedir,Stringname);,文件处理,文件名的处理StringgetName();/得到一个文件的名称(不包括路径)StringgetPath();/得到一个文件的路径名StringgetAbsolutePath();/得到一个文件的绝对路径名StringgetParent();/得到一个文件的上一级目录名文件属性测试booleanexists();/测试当前File对象所指示的文件是否存在booleancanWrite();/测试当前文件是否可写booleancanRead();/测试当前文件是否可读booleanisFile();/测试当前文件是否是文件(不是目录)booleanisDirectory();/测试当前文件是否是目录,文件处理,普通文件信息和工具longlastModified();/得到文件最近一次修改的时间,用与时间点(1970年1月1日,00:00:00GMT)之间的毫秒数表示;longlength();/得到文件的长度,以字节为单位booleandelete();/删除当前文件目录操作booleanmkdir();/根据当前对象生成一个由该对象指定的路径Stringlist();/列出当前目录下的文件示例程序:FileDemo.java,对象流,Java可以将对象作为一个整体通过对象流进行传输和存储。ObjectInputStream和ObjectOutputStream分别是对象流的输入和输出流处理器。构造方法:ObjectInputStream(InputStreamin);ObjectOutputStream(OutputStreamout);当使用对象流写入或读出一个对象时,其前提是这个对象必须是序列化的。,对象序列化,Java1.1增添了一种有趣的特性,名为“对象序列化”(ObjectSerialization)。它面向那些实现了Serializable接口(该接口仅是一个标识接口,没有方法)的对象,可将它们转换成一系列字节,并可在以后完全恢复回原来的样子。这一过程亦可通过网络进行。利用它可以实现“持久化(persistent)”。通过序列化一个对象,将其写入磁盘,以后在程序重新调用时重新恢复那个对象,就能圆满实现一种“持久”效果。,对象序列化,为序列化一个对象,首先要创建某些OutputStream对象,然后将其封装到ObjectOutputStream对象内。此时,只需调用writeObject()即可完成对象的序列化,并将其发送给OutputStream相反的过程是:将一个InputStream封装到ObjectInputStream内,然后调用readObject()。我们最后获得的是一个Object对象,必须做向下类型转换示例:Example8_11.java,Example8_12.java,RandomAccessFile类,RandomAccessFile是用来随机访问那些保存数据记录的文件的,而不用按照流的顺序一次读取。构造方法:RandomAccessFile(Stringname,Stringmode)name是文件名mode是打开方式,“r”只读,“rw”可读写RandomAccessFile(Filefile,Stringmode);file是文件对象mode是打开方式,“r”只读,“rw”可读写注意:RandomAccessFile类并不是单纯的输入或输出流,因此它不是InputStream、OutputStream类的子类。它直接继承了Object,实现了DataInput和DataOutput接口。,RandomAccessFile类,文件指针的操作longgetFilePointer();/用于得到当前的文件指针voidseek(longpos);/用于移动文件指针到指定的位置intskipBytes(intn);/使文件指针向前移动指定的n个字节示例:RandomAccessFileDemo.java,重定向标准I/O,Java1.1在System类中添加了特殊的方法,允许我们重新定向标准输入、输出以及错误IO流。此时要用到下述简单的静态方法调用:setIn(InputStream)setOut(PrintStream)setErr(PrintStream)如果突然要在屏幕上生成大量输出,而且滚动的速度快于人们的阅读速度,输出的重定向就显得特别有用。在一个命令行程序中,如果想重复测试一个特定的用户输入序列,输入的重定向也显得特别有价值。,重定向标准IO示例,将标准输入同一个文件连接起来,并将标准输出和错误重定向至另一个文件。程序代码详见Redirecting.java,程序输出结果如下:,
展开阅读全文