4输入输出流对象应用IO体系结构.docx

上传人:b****5 文档编号:11874621 上传时间:2023-04-08 格式:DOCX 页数:17 大小:89.30KB
下载 相关 举报
4输入输出流对象应用IO体系结构.docx_第1页
第1页 / 共17页
4输入输出流对象应用IO体系结构.docx_第2页
第2页 / 共17页
4输入输出流对象应用IO体系结构.docx_第3页
第3页 / 共17页
4输入输出流对象应用IO体系结构.docx_第4页
第4页 / 共17页
4输入输出流对象应用IO体系结构.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

4输入输出流对象应用IO体系结构.docx

《4输入输出流对象应用IO体系结构.docx》由会员分享,可在线阅读,更多相关《4输入输出流对象应用IO体系结构.docx(17页珍藏版)》请在冰豆网上搜索。

4输入输出流对象应用IO体系结构.docx

4输入输出流对象应用IO体系结构

第四节:

IO体系结构和基础应用

目标:

1.理解流的概念和分类;

2.掌握阻文件复制的实现;理解缓冲原理;

3.掌握对象序列化技术;

4.掌握原始字节流的读写特点。

 

1.流的基础概念:

2

1.stream(流)的概念:

2

2.流的继承体系:

2

3.流的分类:

2

2.InputStream/Outpustream子类:

文件读写3

1.InputStream抽像类:

3

2.InputStream的继承树3

3.使用FileInputStream从文件读取数据4

4.OutPustStream抽像类及基子类5

5.使用FileOutputStream写数据到文件6

3.缓冲流的使用8

1.缓冲流的概念8

2.输入输出缓冲流的使用8

4.对象的串行化:

10

1.对象序列化的用途:

10

2.将对象保存到文件:

10

5.原始数据类型读写流:

11

总结和任务:

12

1.流的基础概念:

1.stream(流)的概念:

java中输入输出相关的类都是java.io包中,java将输入和输出抽像为叫做流的概念,并提供了相应的实现类;流是程序和外界进行数据交换的通道在OOP中的表现,可以将流对象理解从一个水管,它从一个地方输入流据,向另外一个地方输出数据:

输入流是我们在程序中从某个地方(文件、网络)读取数据时使用;输出流是我们将数据发送到某个地方(文件、网络、控制台)时使用。

2.流的继承体系:

在java中,为了对不同来源和性质的流对象调用统一的方法,java中的流首先定义了顶层输入/输出流的接口或抽像类,这样不同性质具体的流对象就会有一个统一的调用方法以便与使用,在使用流对象时,尽量的按照在具体流所实现的接口(抽象类)中定义的方法使用。

3.流的分类:

流按方向分为输入流(InputStream)和输出流(OutputStream):

程序可以使用输入流对象从数据源读取数据,使用输出流对象向目的地写出数据,对应的流类名中一般有Input和Output词;

按性质可以分为:

基础字节流(原始流):

InputStream和OutputStream是java中可以按最小数据单位读取的流,即每次读写一个字节,基础流是直接连结到输入源的流。

过滤流(节点流):

过滤流是用来包装基础流以提供更好的特性,如提供缓冲功能的BufferedInputStream和BufferedOutputStream;过滤流是用来包装基础流或其它流(以其它流对象为构造参数)---它并不直接连结到数据源。

基与具体数据类型的流:

如果要从流中读取指定的数据类型的数据,如int,long型的数值,则要使用DataInput/DataOutput接口的子类如DataInputStream和DataOutputStream;

基与对象读写:

JDK提供了一种强大的功能流,即对象的输入输出流,即ObjectInput/ObjectOutput接口的子类,如我们使用ObjectOutputstream将一个java对象写入到文件中;对象流的读取就是常说的java对象序列化技术。

2.InputStream/Outpustream子类:

文件读写

1.InputStream抽像类:

InputStream基与字节(一个byte一个byte的读取)读取的输入流,它是java.io包中的一个抽像类,在JDK文档中有如下说明(后面流的介绍将不再展示JDK文档,但使用前一定要先查看文档):

我们可以看到它实现了Closeable接口,有9个具体的实现子类---每一个子类对象都可以按照InputStream中定义的方法调用来得到从对应的源得到的数据;

2.InputStream的继承树

InputStream是一个抽像类,它有多种适用与不同用途的具体实现类,InputStream的继承如下图示:

InputStream中定义了如下几个重要的方法:

intavailable():

流中可读取的有效字节长度(以多少个byte计),如具体的InputStream对象源是一个文件,则表示文件中可读取的字节长度;

voidclose():

流对象使用完后要关闭,就像水龙头,用完了要关,否则会占用一些系统资源;

intread():

这个方法调用会返回流中的下一个字节做为一个byte值,如果流己读到末尾,则会返回-1,即表示流中数据己读完;注意,此方法返回虽为int型,实际上是从流中读取的一个byte,即8bit,如果要从流中读取一个int型返回,则需要用后面所讲的DataInput对象的readInt()方法,才是读取四个byte,即32位长度;

intread(byte[] b):

用从流中读到的byte

3.使用FileInputStream从文件读取数据

FileInputStream中InputStream的一个直接字类,可用于构造从文件中读到数据的流,创建一个FileInputStream对象可以使用如下两个常用的构造器:

FileInputStream(File file):

通过一个文件对象做参数构造输入流对象;

FileInputStream(String name):

传入一个字符串(文件路径名)构造连结到指定文件的输入流;

如下代码示例:

创建一个从文件得到的输入流对象,从文件中读取出所有内容做为字符串返回:

packagejava.iotest;

importjava.io.*;

/**

*输入输出流测试

*@authorwww.NetJ

*/

publicclassBaseIO{

//程序主方法

publicstaticvoidmain(Stringargs[])throwsException{

BaseIObi=newBaseIO();

//读取我们当前正在编写的这个java源文件

StringfileName="src\\cn\\netjava\\iotest\\BaseIO.java";

Stringresult=bi.readFile2String(fileName);

System.out.println(result);

}

/**

*读取指定文件名的内容,做为字行串返回

*@paramfileName:

文件名

*@return:

读到的内容做为字符串返回

*@throwsIOException:

可能会抛出IO异常

*/

publicStringreadFile2String(StringfileName)throwsjava.io.IOException{

//构造输入流对象,做为一个Inpustream对象使用

//因为创建的对象是Inpustream的子类的对象,我们用父类型变量引用,方便统一使用

java.io.InputStreamins=newjava.io.FileInputStream(fileName);

//通过文件对象创建输入流

//FilesrcFile=newFile(fileName);

//java.io.InputStreamins=newjava.io.FileInputStream(srcFile);

//根据流中的字节长度,创建一个byte数组,保存读到的数据

byte[]contentByte=newbyte[ins.available()];

//将流中的数据读到数组中

ins.read(contentByte);

//将byte数组转换为字符串

Strings=newString(contentByte);

returns;

}

}

执行程序,将会看到,这个源文件中的内容被输出到的控制台;在InputStream中还应义有一个read()方法,每次调用会读取流源中的一个字节,如果使用read()方法读取,我们可以编写如下方法:

/**

*一次一个字节的读取指定文件名的内容,做为字行串返回

*@paramfileName:

文件名

*@return:

读到的内容做为字符串返回

*@throwsIOException:

可能会抛出IO异常

*/

publicStringreadFileOneByOne(StringfileName)throwsjava.io.IOException{

java.io.InputStreamins=newjava.io.FileInputStream(fileName);

inti=-1;

byte[]contentByte=newbyte[ins.available()];

//读取到第几个byte

intcount=0;

//每次读取一个字节,如返回为-1则表示读完了

while((i=ins.read())!

=-1){

//将读到的1个byte数字入到数组中

contentByte[count]=(byte)i;

count++;

}

//将byte数组转换为字符串

Strings=newString(contentByte);

returns;

}

这两种读法并无高下之分,需要根据具体情况使用。

4.OutPustStream抽像类及基子类

有了InputStream的经验,与其相对的OutputStream就容易掌握了,OutputStream同样是一个抽像象,它只定义了字节输入流统一的几个输出方法;具体的实现则有6个不同的子类,如文档中所示:

 

OutputStream的继承如下图示:

 

OutputStream定义了如下方法调用:

voidclose():

和输入流中的作同一样,输出完了,调用这个方法关闭流

voidflush():

将输出流有可还还保存在(JVM)内存中的数据强制输出到目标中(文件或网络上)

voidwrite(byte[] b):

将byte数组中的内容输出到流中;

voidwrite(byte[] b,int off,int len):

将数组中的一部分写出到流中

voidwrite(int b):

向流中写入一个byte值(注意,此处虽定义为int型,但是写入是做为一个字节,即8位写入的),如果要写入一个int型,则要用后面的DataOutput对象的writeInt()方法将一个int做为4个byte,即32位写入。

5.使用FileOutputStream写数据到文件

FileOutputStream是OutputStream的子类,我们可以利用它将数据写入到文件中,与FileInputStream相对应,它也有如下几个常用构造器:

FileOutputStream(File file):

构造输出到指定文件file对象的输出流.FileOutputStream(File file,boolean append):

append表示输出到文件中是否要覆盖文件中原有的数据;

FileOutputStream(String name)和FileOutputStream(String name,boolean append)与前面两个构造器性质相同,只是用一个字符串文件路径指向的文件构造流对象;

如下示例:

我们可以将从FileInputStream中读取到的数据写入到一个文件中,即简单的文件复制程序:

importjava.io.*;

/**

*输入输出流测试

*@authorwww.NetJ

*/

publicclassBaseIO{

//程序主方法

publicstaticvoidmain(Stringargs[])throwsException{

BaseIObi=newBaseIO();

//读取我们当前正在编写的这个java源文件

StringsrcName="src\\cn\\netjava\\iotest\\BaseIO.java";

//要复制到的目标文件

StringbakName="src\\cn\\netjava\\iotest\\BaseIO.java.bak";

booleanresult=bi.copyFile(srcName,bakName);

System.out.println("复制结果:

"+result);

}

/**

*简单文件复制方法

*@paramsrcFile:

源文件名

*@paramdestFile:

目标文件名

*@throwsIOExcepton:

IO异常

*@return:

是否cp成功

*/

publicbooleancopyFile(StringsrcFile,StringdestFile)throwsIOException{

//创建从源文件来的输入流

InputStreamins=newFileInputStream(srcFile);

//缓冲输出流对象:

如果文件中己有内容则覆盖原来内容

OutputStreamout=newFileOutputStream(destFile);

inti=0;

//从输入流中读取一个字节

while((i=ins.read())!

=-1){

//将这个字节写入到输出流

out.write(i);

}

ins.close();

//清空输出流的缓存并关闭

out.flush();

out.close();

returntrue;

}

}

注意:

当使用输出流将数据输出到文件时,如果目标文件己存在,且FileOutputStream构造器中append为true,则输出的内容会附加到己存在文件的末尾;否则或使用没有这个参数的构造器,都将覆盖己存在的文件;如果目标文件不存在,不论是否有append参数,都将自动创建一个文件;如果程序中的目标文件名字符串中有多级目录,但磁般上并不存在这个目录,程序运行将会报“找不到路径的错误“。

可以看到,流的使用就是这么简单,短短几行代码就完成了文件的复制(读入,写出);但问题不是这么简单,我们复制的这个文件长度很小,请你测试一下用以上方法复制一个大与20M的文件,你会发现速度是简直是相当的慢---该我们介绍缓冲流了:

3.缓冲流的使用

1.缓冲流的概念

缓冲流如我们前面所是,是一种过滤流,常用的是BufferedInputStream/BufferedOutputStream,这两个类分别是InputStream和OutputStream的子类,可用来为InputStream和OutputStream的其它子类流提供高性能的读写包装;

关于“缓冲”简单的理解为:

使用流读写数据时,一般是一个字节(字符流则是一个字符)的读写,这一个字节的读写过程以文件为例,其实需要经过以下几个过程:

输入文件操作系统内存JVM内存代码变量JVM内存操作系统内存输出文件。

经过这么多环节,却仅是传送了一个字节!

这是上面试验复制大文件是速度爆慢的原因,如下图示:

 

缓冲流的机制是在能过缓冲流对象在VM开避了一定大小的缓存区---每次传送缓存区大小的数据,而不是一个一个字节的送,这样效率就有了明显的提高,请看下面的代码示例:

2.输入输出缓冲流的使用

输入缓冲流:

BufferedInputStream本身是InputStream的子类,具体方法就不再介绍,它有以下常用的两种构造器:

BufferedInputStream(InputStream in):

使用一个InputStream类型的输入流对象创建一个默认缓冲区大小的缓冲输入对象;默认缓冲区大小在jdk1.6中为8192K。

BufferedInputStream(InputStream in,int size):

可以指定缓冲区大小构造缓冲输入流对象;

输出缓冲流:

BufferedOutputstream同样是对应的OutputStream的子类,它有如下两个构造器

BufferedOutputStream(OutputStream out):

使用默认大小(8192K)的缓冲区构造缓冲输出流对象。

BufferedOutputStream(OutputStream out,int size):

可指定缓冲大小。

使用缓冲进行文件copy示例:

/**

*使用缓冲流拷文件测试

*@paramsrcFile:

源文件名

*@paramdestFile:

目标文件名

*@throwsIOExcepton:

IO异常

*@return:

是否cp成功

*/

publicbooleanbufferedCopyFile(StringsrcFile,StringdestFile)throwsIOException{

Filesrc=newFile(srcFile);

Filedest=newFile(destFile);

//创建从源文件来的输入流

InputStreamins=newFileInputStream(src);

//构造输入缓冲流

BufferedInputStreambis=newBufferedInputStream(ins);

//构造缓冲输出流对象

OutputStreamout=newFileOutputStream(dest);

BufferedOutputStreambos=newBufferedOutputStream(out);

inti=0;

while((i=bis.read())!

=-1){

//从缓冲输入中读,写出到缓冲输出

bos.write(i);

}

ins.close();

out.flush();

out.close();

returntrue;

}

可以将其和不使用缓冲时复制文件所用的时间做下对比,在我的机器上复制一个30M的文件,两种方法相差有十倍之巨!

4.对象的串行化:

1.对象序列化的用途:

串行化又叫做对象序列化,是可以通过流对象保存java对象的一种方法;对象序列化是java语言的一种强大功能;这种技术是一些软件工具所必须实现的功能:

比如你在编辑一张图片,现在要存盘但下次又要取出修改,程序中的图片不是一张一般的jpeg或gif图片,而是附加了许多属性信息(如phoshop中的图层)的一个程序内部的对象!

通过对象的串行化,这个问题就非常容易解决;再如游戏玩家在休息时需要保存游戏中角色的状态,这也需要用到对象序列化技术。

2.将对象保存到文件:

在java中要实现序列化的对象的类,必须实现java.io.serializable接口;通过查看源代码可以发现这个接口中没有任何方法,实现它的类仅仅是给jVM提供了一个可序列化的标记而己。

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

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

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

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

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

在有些情况下,为了保密需要,类不允许自己对象的某个属性被序列化,就可以在这个属性前面加上transient关键字,加上transient关键字的属性在对象的保存时不会生效,读取时也不会得到数据;

3.对象读写示例:

对象读写一般需使用java.io.ObjectInputStream类的 voidwriteObject(Object obj)方法向流中写入一个对象和java.io.ObjectOutputStream类的ObjectreadObject()读取一个对象,这两个类的构造器分别使用一个InputStream和OutputStream类型的对象做参数:

ObjectInputStream(InputStream in)

ObjectOutputStream(OutputStream out)

这样,我们可用文件输入输出流构造对象输出输出流对象,就可将某个对象保存到文件中。

如下代码示例:

/**

*将一个对象写入到流中,再从流中读取出画

*@paramfileName:

绿写入的文件名

*@return;是否写入成功

*@throwsException

*/

publicbooleanwriteReadObject(StringfileName)throwsException{

//Customer类是一个实现Serializable接口的类

//我们在此保存并读取它的一个对象

Customercustomer=newCustomer();

customer.setName("这个对象保存是设置属性的名字");

FileOutputStreamfos=newFileOutputStream(fileName);

//构造对象输出流

ObjectOutputStreamout=newObjectOutputStream(fos);

//保存对象

out.writeObject(customer);

out.flush();

out.close();

//读取对象

FileInputStreamfis=newFileInputStream(fileName);

ObjectInputStreaminput=newObjectInputStream(fis);

//需要强制转型,从流中读到的是一个Object类型的

CustomerinCus=(Customer)input.readObject();

System.out.println("读取对象:

"+inCus.getName());

returntrue;

}

5.原始数据类型读写流:

DataInputStream和DataOutputStream这两种流主要用来读写指定的数据类型,比如我们要从流中读取一个8个字节的Long型值,再读一个4个字节的int型值,用这两种流就非常方便;在应用中,许多基与TCP/IP的通信协议都是调计为按指写数据类型读取的,有了前面对流的使用经验,这两种流就容易掌握了,请看代码:

/**

*向文件中按数据类型的长度写入数据并读取

*@throwsException

*/

publicvoiddataTypeStream()throwsExcep

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

当前位置:首页 > 工程科技 > 材料科学

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

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