05IO流异常处理.docx
- 文档编号:14822764
- 上传时间:2023-06-27
- 格式:DOCX
- 页数:31
- 大小:27.52KB
05IO流异常处理.docx
《05IO流异常处理.docx》由会员分享,可在线阅读,更多相关《05IO流异常处理.docx(31页珍藏版)》请在冰点文库上搜索。
05IO流异常处理
Ø基本IO操作
RAF提供了文件随机读写功能,但是没有提供复杂数据的读写功能。
Java提供了另外一套可以灵活扩展的API:
IO流。
IO流在节点流基础之上提供了丰富的的扩展功能,利用这些扩展流可以大大简化IO程序的开发。
1.InputStream与OutputStream
1.1.输入与输出
流按照数据流向分为输入流和输入流:
什么是输入:
输入是一个从外界进入到程序的方向,通常我们需要“读取”外界的数据时,使用输入。
所以输入是用来读取数据的。
InputStream代表输入流经常缩写为in/包含核心方法read()/关闭方法close()
什么是输出:
输出是一个从程序发送到外界的方向,通常我们需要”写出”数据到外界时,使用输出。
所以输出是用来写出数据的。
OutputStream代表输出流经常缩写为out/包含核心方法write()/关闭方法close()
这两个流是抽象类,不能直接使用。
在实际工作中使用其实现类:
文件输出流FileOutputStream
1.2.节点流与处理流
按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。
⏹节点流:
可以从或向一个特定的地方(节点)读写数据。
//节点流是流最原始的数据源,提供流最基本的功能。
⏹处理流:
是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。
//也称为高级流,过滤流,处理流是在其他流的基础之上扩展出更高级的功能。
处理流的核心特点是必须依赖于另外一个流,自己不能独立功能,处理流是对另外的流进行扩展。
处理流的构造方法总是要带一个其他的流对象做参数。
一个流对象经过其他流的多次包装,称为流的链接。
2.文件流
2.1.创建FOS对象(重写模式)
FileOutputStream是文件的字节输出流,我们使用该流可以以字节为单位将数据写入文件。
构造方法:
FileOutputStream(Filefile)
创建一个向指定File对象表示的文件中写入数据的文件输出流。
构造方法:
FileOutputStream(Stringfilename):
创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStreamfos=newFileOutputStream("demo.dat");
这里需要注意,若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。
2.2.创建FOS对象(追加模式)
通过上一节的构造方法创建的FOS对文件进行写操作时会覆盖文件中原有数据。
若想在文件的原有数据之后追加新数据则需要以下构造方法创建FOS
构造方法:
FileOutputStream(Filefile,booleanappend)
创建一个向指定File对象表示的文件中写入数据的文件输出流。
例如:
Filefile=newFile("demo.dat");FileOutputStreamfos=newFileOutputStream(file,true);
构造方法:
FileOutputStream(Stringfilename,booleanappend):
创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStreamfos=newFileOutputStream("demo.dat",true);
以上两个构造方法中,第二个参数若为true,那么通过该FOS写出的数据都是在文件末尾追加的。
2.3.创建FIS对象
FileInputStream是文件的字节输入流,我们使用该流可以以字节为单位读取文件内容。
FileInputStream有两个常用的构造方法:
FileInputStream(Filefile)
创建用于读取给定的File对象所表示的文件FIS
另一个构造方法:
FileInputStream(Stringname):
创建用于读取给定的文件系统中的路径名name所指定的文件的FIS
例如FileInputStreamfis=newFileInputStream("demo");//创建一个用于读取demo.dat文件的输入流
2.4.read()和write(intd)方法
FileInputStream继承自InputStream,其提供了以字节为单位读取文件数据的方法read。
intread()
从此输入流中读取一个数据字节,若返回-1则表示EOF(EndOfFile)
FileOutputStream继承自OutputStream,其提供了以字节为单位向文件写数据的方法write。
voidwrite(intd)
将指定字节写入此文件输出流。
这里只写给定的int值的”低八位”
例如
FileOutputStreamfos=newFileOutputStream("demo.dat");
fos.write('A');//这里要注意,char占用2个字节,但这里只写入了1个字节。
2.5.read(byte[]d)和write(byte[]d)方法
FileInputStream也支持批量读取字节数据的方法:
intread(byte[]b)
从此输入流中将最多b.length个字节的数据读入一个byte数组中。
FileOutputStream也支持批量写出字节数据的方法:
voidwrite(byte[]d)
将b.length个字节从指定byte数组写入此文件输出流中。
FileOutputStreamfos=newFileOutputStream("demo.txt");
byte[]data="HelloWorld".getBytes();
fos.write(data);//会将HelloWorld的所有字节写入文件。
将指定byte数组中从偏移量off开始的len个字节写入此文件输出流的方法:
voidwrite(byte[]d,intoffset,intlen)
FileOutputStreamfos=newFileOutputStream("demo.txt");byte[]data="HelloWorld".getBytes();fos.write(data,5,5);//只会将world这5个字节写入文件。
◆使用文件输出节点流写文件案例:
文件输出流节点流,是以文件为目标数据源的节点流,是基本的流,只提供了基本的输出方法write()
publicclassDemo{
publicstaticvoidmain(String[]args)throwsException{
Stringfile="abc/fos.dat";
//利用文件节点流打开一个文件,当文件不存在时候,会自动创建文件
//文件存在时候将文件替换为新文件,当文件不能写时候,出现异常
FileOutputStreamout=newFileOutputStream(file);
//测试基本的byte数据写出方法,将byte写到文件中有效范围(0~255)
out.write(65);
out.write(66);
out.close();
}
}
◆文件输入节点流的读取文件案例:
文件输入节点流,是文件作为数据来源的节点流,也是基础节点流,提供了基本的文件读取功能。
publicclassDemo{
publicstaticvoidmain(String[]args)throwsException{
Stringfile="abc/fos.dat";
//用文件节点输入流打开文件
//如果文件不能打开或者文件不存在就抛出异常!
FileInputStreamin=newFileInputStream(file);
//测试基本的节点流读取方法
//每次从文件中读取一个byte(0~255)
intb1=in.read();
intb2=in.read();
System.out.println(b1);
System.out.println(b2);
in.close();
}
}
◆利用文件流实现文件的复制功能案例:
*在不使用缓冲流的情况下,读写性能很差!
publicclassDemo{
publicstaticvoidmain(String[]args)throwsException{
//打开原始输入文件
FileInputStreamin=newFileInputStream("d:
/TETRIS.zip");
//打开目标的输出文件
FileOutputStreamout=newFileOutputStream("d:
/TETRIS_new.zip");
//从in里读取每个byte写到out流中
intb;
while((b=in.read())!
=-1){
//b代表原始文件中的每个byte
out.write(b);
}
in.close();
out.close();
System.out.println("成功!
");
}
}
这个程序性能有瑕疵。
利用缓存读写方法可以提供文件复制性能:
◆自定义缓存读写案例:
publicclassDemo{
publicstaticvoidmain(String[]args)throwsException{
FileInputStreamin=newFileInputStream("d:
/TETRIS.zip");
FileOutputStreamout=newFileOutputStream("d:
/TETRIS_new.zip");
byte[]buf=newbyte[1024*8];//1Kbyte
//从输入流in中读取尽可能多的byte填充到缓存buf中,返回读取个数1024
//intn=in.read(buf);//1024
//intn=in.read(buf);//1024
//...
//n=in.read(buf);//1~1024
//n=in.read(buf);//-1
intn;
while((n=in.read(buf))!
=-1){
//将buf中从0开始的连续n个byte写到文件流out中
out.write(buf,0,n);
}
in.close();
out.close();
System.out.println("OK!
");
}
}
为了避免最后一次复制多余的byte必须使用out.write(buf,0,n)方法。
3.缓冲流BufferedOutputStream
3.1.BOS基本工作原理
与缓冲输入流相似,在向硬件设备做写出操作时,增大写出次数无疑也会降低写出效率,为此我们可以使用缓冲输出流来一次性批量写出若干数据减少写出次数来提高写出效率。
BufferedOutputStream缓冲输出流内部也维护着一个缓冲区,每当我们向该流写数据时,都会先将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。
3.2.BOS实现写出缓冲
3.3.BOS的flush方法
有时我们需要在执行完某些写出操作后,就希望将这些数据确实写出,而非在缓冲区中保存直到缓冲区满后才写出。
这时我们可以使用缓冲流的一个方法flush。
voidflush()
清空缓冲区,将缓冲区中的数据强制写出。
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream("demo.dat"));
bos.write('a');//并没有向磁盘写出,而是写入到了BOS的缓存中
bos.flush();//强制将缓存中的数据一次性写出,这时‘a’才会被写入磁盘
bos.close();//实际上,close()方法在变比缓冲流前也调用了flush()
3.4.BIS基本工作原理
在读取数据时若以字节为单位读取数据,会导致读取次数过于频繁从而大大的降低读取效率。
为此我们可以通过提高一次读取的字节数量减少读写次数来提高读取的效率。
BufferedInputStream是缓冲字节输入流。
其内部维护着一个缓冲区(字节数组),使用该流在读取一个字节时,该流会尽可能多的一次性读取若干字节并存入缓冲区,然后逐一的将字节返回,直到缓冲区中的数据被全部读取完毕,会再次读取若干字节从而反复。
这样就减少了读取的次数,从而提高了读取效率。
BIS是一个处理流,该流为我们提供了缓冲功能。
3.5.BIS实现输入缓冲
使用缓冲流来实现文件复制:
FileInputStreamfis=newFileInputStream("java.zip");
BufferedInputStreambis=newBufferedInputStream(fis);
FileOutputStreamfos=newFileOutputStream("copy_java.zip");
BufferedOutputStreambos=newBufferedOutputStream(fos);
intd=-1;while((d=bis.read())!
=-1){
bos.write(d);}bis.close();//读写完毕后要关闭流,只需要关闭最外层的流即可bos.close();
4.对象流
4.1.对象序列化概念
对象是存在于内存中的。
有时候我们需要将对象保存到硬盘上,又有时我们需要将对象传输到另一台计算机上等等这样的操作。
这时我们需要将对象转换为一个字节序列,而这个过程就称为对象序列化。
相反,我们有这样一个字节序列需要将其转换为对应的对象,这个过程就称为对象的反序列化。
4.2.使用OOS实现对象序列化
ObjectOutputStream是用来对对象进行序列化的输出流。
(将对象变成byte)
其实现对象序列化的方法为:
voidwriteObject(Objecto)
该方法可以将给定的对象转换为一个字节序列后写出。
4.3.使用OIS实现对象反序列化
ObjectInputStream是用来对对象进行反序列化的输入流。
(将byte拼接为对象)
其实现对象反序列化的方法为:
ObjectreadObject()
该方法可以从流中读取字节并转换为对应的对象。
4.4.Serializable接口
ObjectOutputStream在对对象进行序列化时有一个要求,就是需要序列化的对象所属的类必须实现Serializable接口。
实现该接口不需要重写任何方法。
其只是作为可序列化的标志。
建议:
(必须遵守)实现序列化接口是添加序列化序列化版本号,可以保证对象序列化、反序列化的稳定。
减少更改类对序列化的影响。
◆对象序列化案例:
publicclassDemo0{
publicstaticvoidmain(String[]args)throwsException{
Personp1=newPerson("范传奇",10);
Personp2=newPerson("李洪鹤",10);
p1.friend=p2;
Stringfile="abc/obj.dat";
//将对象写到文件中
FileOutputStreamfos=newFileOutputStream(file);
BufferedOutputStreambos=newBufferedOutputStream(fos);
//对象输出流
ObjectOutputStreamoos=newObjectOutputStream(bos);
//将对象写到文件中
oos.writeObject(p1);
oos.writeObject(p2);
oos.close();
}
}
◆对象反序列化案例:
publicclassDemo{
publicstaticvoidmain(String[]args)throwsException{
Stringfile="abc/obj.dat";
FileInputStreamfis=newFileInputStream(file);
BufferedInputStreambis=newBufferedInputStream(fis);
ObjectInputStreamois=newObjectInputStream(bis);
//读取对象从文件读取一系列byte数据拼接为对象
Personp1=(Person)ois.readObject();
Personp2=(Person)ois.readObject();
System.out.println(p1);
System.out.println(p2);
ois.close();
}
}
Ø文件数据IO操作
1.Reader和Writer
1.1.字符流原理
Reader是所有字符输入流的父类,而Writer是所有字符输出流的父类。
字符流是以字符(char)为单位读写数据的。
一次处理一个unicode字符流都是高级流,其底层都是依靠字节流进行读写数据的,所以底层仍然是基于字节读写数据的。
字符流只能处理文本文件!
1.2.常用方法
Reader的常用方法:
1)intread()
读取一个字符,返回的int”值低16”位有效。
2)intread(char[]chs)
从该流中读取一个字符数组length个字符并存入该数组,返回值为实际读取到的字符量。
Writer的常用方法:
1)voidwrite(intc)
写出一个字符,写出给定int值”低16”位表示的字符。
2)voidwrite(char[]chs)
将给定字符数组中所有字符写出。
3)voidwrite(Stringstr)
将给定的字符串写出
4)voidwrite(char[]chs,intoffset,intlen):
将给定的字符数组中从offset处开始连续的len个字符写出
2.转换流
2.1.字符转换流原理
InputStreamReader:
字符输入流,使用该流可以设置字符集,并按照指定的字符集从流中按照该编码将字节数据转换为字符并读取。
OutputStreamWriter:
字符输出流,使用该流可以设置字符集,并按照指定的字符集将字符转换为对应字节后通过该流写出。
2.2.指定字符编码
InputStreamReader的构造方法允许我们设置字符集:
InputStreamReader(InputStreamin,StringcharsetName)
基于给定的字节输入流以及字符编码创建ISR
InputStreamReader(InputStreamin)
该构造方法会根据系统默认字符集创建ISR
OutputStreamWriter:
的构造方法:
OutputStreamWriter(OutputStreamout,StringcharsetName)
基于给定的字节输出流以及字符编码创建OSW
OutputStreamWriter(OutputStreamout)
该构造方法会根据系统默认字符集创建OSW
2.3.使用OutputStreamWriter
publicvoidtestOutput()throwsIOException{
FileOutputStreamfos=newFileOutputStream("demo.txt");
OutputStreamWriterwriter
//这里使用的字符编码为UTF-8
=newOutputStreamWriter(fos,"UTF-8");
Stringstr="大家好!
";//UTF-8中文为3个字节,英文符号占1个字节
writer.write(str);//写出后该文件大小应该为10字节
writer.close();
}
2.4.使用InputStreamReader
publicvoidtestInput()throwsIOException{
FileInputStreamfis=newFileInputStream("demo.txt");
/*这里设置了字符编码为GBK之后再通过ISR读取demo.txt文件时就使用GBK编码读取字符了
InputStreamReaderreader=newInputStreamReader(fis,"GBK");
intc=-1;
while((c=reader.read())!
=-1){
System.out.print((char)c);
}
reader.close();
}
3.PrintWriter
3.1.创建PrintWriter对象
PrintWriter是具有自动行刷新的缓冲该字符输出流。
其提供了比较丰富的构造方法:
✓PrintWriter(Filefile)
✓PrintWriter(StringfileName)
✓PrintWriter(OutputStreamout)
✓PrintWriter(OutputStreamout,booleanautoFlush)
✓PrintWriter(Writerwriter)
✓PrintWriter(Writerwriter,booleanautoFlush)
其中参数为OutputStream与Writer的构造方法提供了一个可以传入boolean值参数,
该参数用于表示PrintWriter是否具有自动行刷新。
3.2.PrintWriter的重载print和println方法
使用PrintWriter写出字符串时我们通常不使用Writer提供的write()相关方法,而是使用print和println等方法,PrintWriter提供了若干重载的print与println方法,其中println方法是在写出数据后自动追加一个系统支持的换行符。
重载方法有:
✓voidprint(inti)//打印整数
✓voidprint(charc)//打印字符
✓voidprint(booleanb)//打印boolean值
✓voidprint(char[]c)//打印字符数组
✓voidprint(doubled)//打印double值
✓voidprint(floatf)//打印float值
✓voidprint(long
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 05 IO 异常 处理