12 第十二章 高级IO流.docx

上传人:b****6 文档编号:4376631 上传时间:2022-12-01 格式:DOCX 页数:15 大小:50.68KB
下载 相关 举报
12 第十二章 高级IO流.docx_第1页
第1页 / 共15页
12 第十二章 高级IO流.docx_第2页
第2页 / 共15页
12 第十二章 高级IO流.docx_第3页
第3页 / 共15页
12 第十二章 高级IO流.docx_第4页
第4页 / 共15页
12 第十二章 高级IO流.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

12 第十二章 高级IO流.docx

《12 第十二章 高级IO流.docx》由会员分享,可在线阅读,更多相关《12 第十二章 高级IO流.docx(15页珍藏版)》请在冰豆网上搜索。

12 第十二章 高级IO流.docx

12第十二章高级IO流

第十二章:

高级I/O流

学习目标

⏹java.io包内类

⏹理解流的概念和节点流,过滤流的使用

⏹流与字符流并恰当使用和目录

⏹更新文本和数据文件

⏹用Serialization接口序列化编码对象的状态

I/O基础知识

Java语言中数据流是发送或接收数据的管道。

通常,你的程序是流的一个端点,其它程序或文件是流的另一个端点。

流的单向性:

源端点和目的端点分别叫做inputstream(输入流)和outputstream(输出流)。

你可以从输入流读,但你不能对它写;同样,你可以向输出流写,但不能从输出流读。

数据流的分类如图

InputStream和OutputStream:

字节流。

其它字节流都是InputStream或OutputStream的子类。

Reader和Writer:

字符流。

其它字符流都是Reader或Writer的子类。

字节流

InputStream

InputStream有三个方法访问它的数据:

intread():

简单读方法,返回一个int值,它是从流里读出的一个字节。

如果遇到文件结束则返回-1。

intread(byte[]):

将数据读入到字节数组中,并返回所读的字节数。

intread(byte[],intoffset,intlength)将数据读入到字节数组中,并返回所读的字节数。

Offset是数组的偏移量,length是读取的长度。

voidclose()你完成流操作之后,就关闭这个流。

如果你有一个流所组成的栈,使用过滤器流,就关闭栈顶部的流。

这个关闭操作会关闭其余的流。

intavailable()

这个方法报告立刻可以从流中读取的字节数。

在这个调用之后的实际读操作可能返回更多的字节数。

skip(long)这个方法丢弃了流中指定数目的字符。

booleanmarkSupported()

voidmark(int)

voidreset()

如果流支持"回放"操作,则这些方法可以用来完成这个操作。

如果mark()和reset()方法可以在特定的流上操作,则markSupported()方法将返回ture。

mark(int)方法用来指明应当标记流的当前点和分配一个足够大的缓冲区,它最少可以容纳参数所指定数量的字节。

在随后的read()操作完成之后,调用reset()方法来返回你标记的输入点。

OutputStream

voidwrite(int)

voidwrite(byte[])

voidwrite(byte[],int,int)

这些方法写输出流。

和输入一样,总是尝试以实际最大的块进行写操作。

voidclose()当你完成写操作后,就关闭输出流。

如果你有一个流所组成的栈,就关闭栈顶部的流。

这个关闭操作会关闭其余的流。

voidflush()

有时一个输出流在积累了若干次之后才进行真正的写操作。

flush()方法允许你强制执行写操作。

字符流

Reader

intread()

intread(char[])

intread(char[],intoffset,intlength)

简单读方法返回一个int值,它包含从流里读出的一个字符或者-1,其中-1表明文件结束。

其它两种方法将数据读入到字符数组中,并返回所读的字符数。

第三个方法中的两个int参数指定了所要填入的数组的子范围。

voidclose()

booleanready()

voidskip(long)

booleanmarkSupported()

voidmark(int)

voidreset()

这些方法与InputStream中的对应方法相似

Writer

voidwrite(intc)

voidwrite(char[])

voidwrite(char[],intoffset,intlength)

voidwrite(Stringstring)

voidwrite(Stringstring,intoffset,intlength)

voidclose()

voidflush()

所有这些方法与OutputStream中的方法类似。

节点流

Java2SDK中有三种基本类型的节点:

文件(file)、内存(memory)、管道(pipe)。

过程流

过程流在其它流之上,完成排序、变换等操作。

过程流也被称做过滤流。

当你需要改变输入流的原始数据时,你可以将一个过滤输入流连接到一个原始的输入流上。

用过滤流将原始数据变换成你需要的格式。

其分类如图

基本字节流类

分类如图

 

FileInputStream和FileOutputStream

这两个节点流用来操纵磁盘文件。

这些类的构造函数允许你指定它们所连接的文件。

要构造一个FileInputStream,所关联的文件必须存在而且是可读的。

如果你要构造一个FileOutputStream而输出文件已经存在,则它将被覆盖。

主要用于操作二进制或者带有格式的文件:

如压缩文件,可执行文件等。

FileInputStreaminfile=newFileInputStream("myfile.dat");

FileOutputStreamoutfile=newFileOutputStream("results.dat");

BufferInputStream和BufferOutputStream

带有缓冲区的流,BufferInputStream一次可以读入一定长度的数据(默认2048字节),BufferOutputStream一次可以一定长度的数据(默认512字节),可以提高I/O操作的效率。

需要和其它的流类配合使用。

BufferOutputStream在使用时,为了确保把数据写出去,建议最后执行flush()将缓冲区中的数据全部写出去。

PipedInputStream和PipedOutputStream

管道流用来在线程间进行通信。

一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。

要使管道流有用,必须有一个输入方和一个输出方。

DataInputStream和DataOutputStream

用来对java的基本数据类型读写的类

DataInputStream方法

bytereadByte()

longreadLong()

doublereadDouble()

StringreadUTF(DataInputin)

DataOutputStream方法

voidwriteByte(byte)

voidwriteLong(long)

voidwriteDouble(double)

voidwriteUTF(Stringstr)

PrintStream

可以自动进行字符转换的动作,默认会使用操作系统的编码处理对应的字符。

importjava.io.*;

publicclassPrintStreamDemo{

publicstaticvoidmain(String[]args)throwsFileNotFoundException{

PrintStreamout=newPrintStream(newFileOutPutStream("1.txt"));

out.println

(1);

out.close();

}

}

基本字符流类

阐述了Reader和Writer字符流的体系结构。

InputStreamReader和OutputStreamWriter

用于字节流与字符流之间的转换接口。

当你构造一个InputStreamReader或OutputStreamWriter时,转换规则定义了16位Unicode和其它平台的特定表示之间的转换。

InputStreamReader从一个数据源读取字节,并自动将其转换成Unicode字符。

如果你特别声明,InputStreamReade会将字节流转换成其它种类的字符流。

OutputStreamWriter将字符的Unicode编码写到输出流,如果你的使用的不是Unicode字符,OutputStreamWriter会将你的字符编码转换成Unicode编码。

BufferedReader和BufferedWriter

因为在各种格式之间进行转换和其它I/O操作很类似,所以在处理大块数据时效率最高。

在InputStreamReader和OutputStreamWriter的结尾链接一个BufferedReader和BufferedWriter是一个好主意。

记住对BufferedWriter使用flush()方法。

FileReader和FileWriter

以字符的方式操作文件的类,主要用于操作文本文件。

PrintWriter

与PrintStream相类似,使用println()输出内容。

URL输入流

除了基本的文件访问之外,Java技术提供了使用统一资源定位器(URL)来访问网络上的文件。

当你使用Applet的getDocumentBase()方法来访问声音和图象时,你已经隐含地使用了URL对象。

StringimageFile=newString("images/Duke/T1.gif");

images[0]=getImage(getDocumentBase(),imageFile);

当然,你也可以直接使用URL如下:

.URLimageSource;

try{

imageSource=newURL("

}catch(MalformedURLExceptione){}

images[0]=getImage(imageSource,"Duke/T1.gif");

使用RandomAccessFile随机访问文件

你经常会发现你只想读取文件的一部分数据,而不需要从头至尾读取整个文件。

你可能想访问一个作为数据库的文本文件,此时你会移动到某一条记录并读取它的数据,接着移动到另一个记录,然后再到其他记录――每一条记录都位于文件的不同部分。

Java编程语言提供了一个RandomAccessFile类来处理这种类型的输入输出。

创建一个随机访问文件

你可以用如下两种方法来打开一个随机存取文件:

用文件名

myRAFile=newRandomAccessFile(Stringname,Stringmode);

用文件对象

myRAFile=newRandomAccessFile(Filefile,Stringmode);

mode参数决定了你对这个文件的存取是只读(r)还是读/写(rw)。

例如,你可以打开一个数据库文件并准备更新:

RandomAccessFilemyRAFile;

myRAFile=newRandomAccessFile("db/stock.dbf","rw");

存取信息

RandomAccessFile对象按照与数据输入输出对象相同的方式来读写信息。

你可以访问在DataInputStrem和DataOutputStream中所有的read()和write()操作。

Java编程语言提供了若干种方法,用来帮助你在文件中移动。

longgetFilePointer();返回文件指针的当前位置。

voidseek(longpos);设置文件指针到给定的绝对位置。

这个位置是按照从文件开始的字节偏移量给出的。

位置0标志文件的开始。

longlength()返回文件的长度。

位置length()标志文件的结束。

添加信息

你可以使用随机存取文件来得到文件输出的添加模式。

myRAFile=newRandomAccessFile("java.log","rw");

myRAFile.seek(myRAFile.length());

对象串行化

java.io.Serializable接口支持将一个Java技术对象存放到一个流中。

将一个对象存放到某种类型的永久存储器上称为"保持"。

如果一个对象可以被存放到磁盘或磁带上,或者可以发送到另外一台机器并存放到存储器或磁

盘上,那么这个对象就被称为可保持的。

java.io.Serializable接口没有任何方法,它只作为一个"标记",用来表明实现了这个接口的类可以串行化。

类中没有实现Serializable接口的对象不能被保持。

当一个对象被串行化时,只有对象的数据被保存;方法和构造函数不属于串行化流。

如果一个数据变量是一个对象引用,那么这个对象的数据成员也会被串行化。

树或者对象数据的结构,包括这些子对象,构成了对象图。

因为有些对象类所表示的数据在不断地改变,所以它们不会被串行化;例如,java.io.FileInputStream、java.io.FileOutputStream和java.lang.Thread等流。

如果一个可串行化对象包含某个不可串行化元素的引用,那么整个串行化操作就会失败,而且会抛出一个NotSerializableException。

如果对象图包含一个不可串行化的引用,只要这个引用已经用transient关键字进行了标记,那么对象仍然可以被串行化。

publicclassMyClassimplementsSerializable{

publictransientThreadmyThread;

privateStringcustomerID;

privateinttotal;

}

域存取修饰符对于被串行化的对象没有任何作用。

写入到流的数据是字节格式,而且字符串被表示为UTF(文件系统安全的通用字符集转换格式)。

transient关键字防止对象被串行化。

publicclassMyClassimplementsSerializable{

publictransientThreadmyThread;

privatetransientStringcustomerID;

privateinttotal;

}

实例分析

例1:

从第一个命令行参数代表的文件中读字符,然后写入第二个参数代表的文件。

问题分析

本题中需要从文件读,写数据,需要使用到与文件有关的流FileReader/FileWriter。

可以通过运行时参数提供文件的名称。

使用带有Buffer功能的流

为了提高读写数据的效率,可以使用带有buffer功能的流完成文件读写,并且可以以行为单位读写数据。

使用类BufferedReader,BufferedWriter

I/O流的链

在程序中很少使用单独一个流对象,实际做法是将几个流对象串联起来处共同理数据。

这样做会提高程序的效率。

数据源->FileInputStream->BufferedInputStream->DataInputStream->程序

数据源<-DataOutputStream<-BufferedOutputStream<-FileOutputStream<-程序

编写代码

importjava.io.*;

publicclassTestBufferedStreams{

publicstaticvoidmain(String[]args){

try{

FileReaderinput=newFileReader(args[0]);

BufferedReaderbufInput=newBufferedReader(input);

FileWriteroutput=newFileWriter(args[1]);

BufferedWriterbufOutput=newBufferedWriter(output);

Stringline=bufInput.readLine();

while(line!

=null){

bufOutput.write(line,0,line.length());

bufOutput.newLine();

line=bufInput.readLine();

}

bufInput.close();

bufOutput.close();

}catch(IOExceptione){

e.printStackTrace();

}

}

}

编译运行

javacTestBufferedStreams.java

javaTestBufferedStreamsuser.batuserbak.bat

例2:

使用管道流完成线程之间的通讯。

1问题分析

本题中需要一个线程向管道写入数据,另外一个线程从管道中读出数据,需要使用到与管道有关的流PipedInputStream和PipedOutputStream。

2使用管道流

PipedInputStream和PipedOutputStream

管道流用来在线程间进行通信。

一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。

要使管道流有用,必须有一个输入方和一个输出方。

PipedInputStreamin=newPipedInputStream();

PipedOutputStreamout=newPipedOutputStream(in);

3编写代码

importjava.io.*;

publicclassTestPipeStream{

publicstaticvoidmain(String[]args){

try{

PipedInputStreamin1=newPipedInputStream();

PipedOutputStreamout1=newPipedOutputStream(in1);

PipedInputStreamin2=newPipedInputStream();

PipedOutputStreamout2=newPipedOutputStream(in2);

ThreadCtc=newThreadC(out1);

ThreadZtz=newThreadZ(out2,in1);

ThreadQtq=newThreadQ(in2);

tc.start();

tz.start();

tq.start();

}catch(Exceptione){

e.printStackTrace();

}

}

staticclassThreadCextendsThread{

DataOutputStreamdos=null;

publicThreadC(OutputStreamos){

dos=newDataOutputStream(os);

}

publicvoidrun(){

while(true){

try{

doubled=Math.random();

dos.writeDouble(d);

sleep

(2);

}catch(Exceptione){

e.printStackTrace();

}

}

}

};

staticclassThreadZextendsThread{

DataOutputStreamdos=null;

DataInputStreamdis=null;

publicThreadZ(OutputStreamos,InputStreamis){

dos=newDataOutputStream(os);

dis=newDataInputStream(is);

}

publicvoidrun(){

while(true){

try{

doubled=dis.readDouble();

dos.writeDouble(d);

}catch(Exceptione){

e.printStackTrace();

}

}

}

};

staticclassThreadQextendsThread{

DataInputStreamdis=null;

publicThreadQ(InputStreamis){

dis=newDataInputStream(is);

}

publicvoidrun(){

while(true){

try{

doubled=dis.readDouble();

System.out.println(d);

}catch(Exceptione){

e.printStackTrace();

}

}

}

};

}

编译运行

javacTestPipeStream.java

javaTestPipeStream

例3:

保存所有的Person对象到文件并以对象的方式读出来

1问题分析

本题中需要对文件读,写对象数据,需要使用到与对象有关的流ObjectInputStream/ObjectOutputStream。

2使用对象的读写流

ObjectOutputStream用于将一个对象输出,输出对象使用的方法为writeObject(Objectobj)

ObjectInputStream用于读取一个对象,读取对象使用的方法为readObject()

注意:

被读写的对象必须是已序列化的类的对象,即要实现要Serializable接口。

3编写代码

importjava.io.*;

importjava.util.*;

classPersonimplementsSerializable{

Stringname=null;

publicPerson(Strings){

name=s;

}

publicStringtoString(){

returnname;

}

}

publicclassTestObjectStream{

publicstaticvoidmain(String[]args){

ObjectOutputStreamoos=null;

ObjectInputStreamois=null;

try{

Filef

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1