第十二章 输入输出流.docx
《第十二章 输入输出流.docx》由会员分享,可在线阅读,更多相关《第十二章 输入输出流.docx(31页珍藏版)》请在冰点文库上搜索。
第十二章输入输出流
输入输出流
教学提示:
对于任何一种程序设计语言而言,数据的输入输出都是必不可少的功能,对于JAVA程序设计来说,也是如此。
JAVA是面向对象的程序设计语言,它对输入输出的处理是通过数据流来实现的。
教学目标:
本章将重点介绍数据流的概念以及应用,以及对字节流、字符流、管道流和文件的操作。
当一个程序需要输入数据时,除了让使用者利用鼠标或键盘等输入装置输入以外.还可以从数据流中获得;如果需要输出数据时,除了可以输出到屏幕等输出装置,也可以输出到数据流中,所以数据流可以分成输入数据流与输出数据流两种。
到底什么是数据流(stream)呢?
简单的说就是一段数据,以输入数据流来说,当我们要取得的时候就提供一部分,就好像水龙头一开就会有水流出来一般,直到用完为止。
Java把对磁盘和网络数据的存取,都变成了对数据流的存取,这样的好处是,不管今天要存取的来源是磁盘或网络,程序代码都是一样的,只有建立连结的部分不一样而己。
Java把有关文件存取和数据流的部分放在办java.io这个包里面。
Java.io包中有两个主要部分:
字符流和字节流。
字符是16位的Unicode字符,而字节是8位的。
字符流被用于文本的输入输出,而字节流被用于数据的输入输出。
字节流被称为输入流(inputstream)或输出流(outputstream),而字符流被称为reader或writer。
对于任何一个输入流,都有相关的输出流,而且对大多数输入流和输出流,都有类似的功能相对应的reader或writer字符流。
OutputStream类
InputStream类
ObjectOutputStream
ObjectInputStream
ByteArrayOutputStream
ByteArrayInputStream
PipeOutputStream
PipeInputStream
FileOutputStream
FileInputStream
FilterOutputStream
FilterInputStream
Java.io包里面的类,有很多method都会产生IOException,所以便用时都必须用try--catch指令去处理。
造成的原因可能很多,例如磁盘坏掉、网络断线等等而导致数据无法正常存取,为了让程序能够在发生异常时还能执行下去,所以必须将IOException拦截下来。
12.1读数据——Reader类
Reader类,顾名思义,就是用来从输入数据流读取数据的类,但因为数据来源有许多种,所以Java将Reader类定义成抽象类,让它的所有子类有实现的依据。
Reader类的实现如下:
publicabstractclassReaderextendsObject
常用方法有:
1.publicabstractvoidclose()throwsIOException
结束对数据流的读取,当我们不再需要用这个Reader去读取某个数据流时,都会调用这个方法。
因为数据流的来源不一,所以实现成abstract测的形式,好让子类去覆盖。
2.publicintRead()throwsIOException
从数据流读取一个字节并返回。
返回值的范围从0到255,但如果已经到达数据流的结尾,没有数据可以读取了,则会返回-1。
这个方法会一直等待直到读取到一个字节、产生IOException或数据读完为止。
3.publicintRead(char[]cbuf)throwsIOException
从数据流读取数个字符放进数组cbuf中,并返回所读取到的字符数目,最多可读取和cbuf长度相同的字符数,但如果没有读取到,则返回-1。
这个方法会一直等待直到读取到字符、产生IOException、或数据读完为止。
4.publicbooleanready()throwsIOException
检查数据流是否已经准备好要被读取,是则返回true,否则返回false。
如果返回值为true,则紧接着的read指令将不会受到阻碍。
5.publiclongskip(longn)throwsIOExceptlon
略过n个字节不读取,会返回实际略过的字节数目。
因为数据流中剩下的数据可能不到n个字节那么多,所以此时返回值会小于n。
【例12-1】在一个字符流里记录空格个数。
importjava.io.*
classCountSpace{
publicStaticvoidmain(String[]args)throwsIOException{
Readerin;
if(args.length==0)
in=newInputStreamReader(System.in);
else
in=newFileReader(args[0]);
intch;
inttotal;
intspaces=0;
for(total=0;(ch=in.read())!
=-1;total++){
if((Character.isWhitespace((char)ch))
spaces++;
}
System.out.println(total+”chars,”+spaces+”spaces”);
}
}
该程序从命令行获得文件名,in表示字符流,若文件名没有,标注输入流(System.in)被封装到InputStreamReader中之后,就能用于将输入字节流转换为输入字符流,若有文件名,就创建一个FileReader对象,它是Reader的子类。
其中使用Character类的isWhitespace方法测试字符是否为空格。
若以源代码文件做选择,显示结果为453chars,111spaces
12.2输入数据流——InputStream类
InputStream类是所有输入数据流的父类,所以它也被实现成抽象类,定义了所有输入数据流都具有的共通特性。
通常不同的输入数据流都会有相对的读取类,例如InputStream有InputStreamReader,BufferedInputStream和BufferedReader等等。
所以我们除了可以直接用输入数据流读取数据外,也可以利用相对的读取类去取得数据,也因此输入数据流的方法和读取类的方法几乎一样。
InputStream类的实现如下:
publicabstractclassInputStreamextendsObject
常用方法请参考Reader类方法。
【例12-2】下面的程序演示了使用输入流来对文件中的总字节数进行计数。
importjava.io.*;
classCountBytes{
publicstaticvoidmain(String[]args)throwsIOException{
InputStreamin;
if(args.length==0)//无参数
in=System.in;//在没有指定具体文件的情况下,使用System.in
else
in=newFileInputStream(args[0]);//打开文件
inttotal=0;
while(in.read()!
=-1)//对文件中的字节数进行计数
total++;
System.out.println(total+”bytes”);
}
}
注意:
如果不带参数,则需要通过键盘输入,用Ctrl+Z结束输入。
12.3文件——File类
File类指的是磁盘上的目录或文件,这一节里面所提到的”路径”,就是目录或文件所在的位置,可以是相对于目前工作目录的”相对路径”,也可以是”绝对路径”。
路径中的分隔字符是’\’或’/’,视操作系统而定,Java会自动帮您转换,所以就算您在Windows操作系统下写程序时用’\’,拿到UNIX操作系统下仍然可以执行。
File类的实现如下:
publicclassFileextendsObjectimplementsSerializable,Comparable
12.3.1File类的构造函数
File类的构造函数有下列三种:
File(Fileparent,Stringchild)
//建立一个以parent加上child为路径的File组件。
File(Stringpathname)
//建立一个以pathname为路径的File组件。
File(StringParent,Stringchild)
//建立一个以parent加上child为路径的File组件。
12.3.2File类的方法
1.publicbooleancanRead()
检查File组件所代表的文件是否可以读取,是则返回true,否则返回免false。
2.publicbooleancanWrite()
检查问File组件所代表的文件是否可以写入或修改,是则返回true,否则返回false。
3.publicbooleancreateNewFile()throwsIOException
以File组件的内容为文件名建立一个新文件。
如果原文件已经存在,则返回false,否则如果建立成功,则返回true。
4.publicbooleandelete()
将File组件代表的文件或目录删除,成功则返回true,否则返回false。
如果File组件代表的是一个目录,则该目录必须是空的。
5.publicbooleanexists()
检查File组件所代表的路径是否已经存在,是则返回true,否则返回false。
6.publicstringgetAbsolutePath()
将File组件的内容转换成绝对路径,也就是如果原本File组件所代表的为相对路径,则在前面加上目前的路径。
7.publicstringgetName()
返回File组件所代表的目录或文件名称,即整个路径的最后一段字符串。
例如:
File的内容为“work/document/test.txt”,则这个method会返回“test.txt”。
8.publicStringgetParent()
返回File组件历代表的目录或文件的所在路径,即整个路径的除了最后一段字符串以外的部分。
例如File的内容为“work/document/test.txt”,则这个method会返回“work/document”。
9.publicStringgetPath()
返回File组件所代表的路径。
10.publicbooleanisAbsolute()
检查File组件所代表的路径是否为绝对路径,是则返回true,否则返回false。
11.publicbooleanisDirectory()
检查File组件所代表的路径是否为目录,是则返回true,否则返回false。
12.publicbooleanisFile()
检查File组件所代表的路径是否为文件,是则返回true,否则返回false。
13.publicbooleanisHidden()
检查File组件所代表的路径是否为隐藏的状态,是则返回血true,否则返回false。
14.publiclonglength()
返回File组件所代表的路径共占了几个字节,如果路径不存在,或该路径代表的是一个目录,则会返回0。
15.publicbooleanmkdirs()
以File组件的内容为目录名称,把沿途的目录都建立好,如果成功则返回true,否则返回false。
16.publicbooleanrenameTo(Filedest)
把File组件所代表的路径名称改成dest历代表的路径,如果成功则返回的true,否则返回fa1se。
17.publicbooleansetReadOnly()
将File组件所代表的路径设置成只读的状态,如果成功则返回true,否则返回false。
一旦设置成只渎状态,就不能去改变路径的内容,但在某些操作系统下,允许使用者将只读的路径删除掉。
【例12-3】现在我们就来实际练习一下File类的用法。
importjava.awt.*;
importjava.io.*;
publicclassFileTestextendsFrame{
publicstaticvoidmain(Stringargs[]){
FileTestTest=newFileTest();
TextAreaTa=newTextArea();
Filef=newFile("work","test");//建立一个路径为"work/test"的File组件
try{
Ta.append(f.getPath()+"\n");
Ta.append(f.getParent()+"\n");
Ta.append(f.getName()+"\n");
Ta.append(f.getAbsolutePath()+"\n");
f.createNewFile();
Ta.append(f.exists()+"\n");
Ta.append(f.length()+"\n");
}
catch(IOExceptione){
System.out.println("exception");
}
Test.add(Ta,BorderLayout.CENTER);
Test.setSize(300,300);
Test.setVisible(true);
}
}
运行结果如图12-1所示:
图12-1File类的使用
12.4FileReader类
知道如何使用File类后,我们就可以利用FileReader类把文件的内容取出来了。
FileReader类的实现如下:
publicclassFileReaderextendsInputStreamReader
12.4.1FileReader类的构造函数
FileReader类的构造函数有下列两种:
FileReader(Filefile)throwsFileNotFoundException
建立一个用来读取file所代表的文件的FileReader组件,如果该文件不存在,则会产生FileNotFoundException。
FileReader(StringfileName)throwsFileNotFoundException
建立一个用来读取以fileName为文件名的文件的FileReader组件,文件不存在,则会产生FileNotFoundException。
12.4.2FileReader类的方法
其实FileReader类本身并没有方法,只有从Reader类和InputStreamReader类继承来的方法,难道因此我们只能用read方法把文件中的字符一个个读取出来吗?
没关系,我们还可以配合其它的读取类来使用,这样一来不但可以读一个字符,也可以读取一整行。
所以下一节介绍完BufferedReader后,我们再来写一个读取文件的实例吧。
12.5BufferedReader类
BufferedReader也是一个从数据流读取数据的类,但它会事先将一部分数据读进来放在缓冲区里,等到程序真正要选取数据时,就可以一次返回很多字节的数据。
BufferedReader类的实现如下:
publicclassBufferedReaderextendReader
12.5.1BufferedReader类的构造函数
BufferedReader类的构造函数有下列两种:
BufferedReade(Readerin)
建立一个BufferedReader组件,并且以in的输入数据流为数据的来源。
BufferedReader(Readerin,intsz)
和前面差不多,但可以设置缓冲区的大小。
除非您有特殊的需要,不然前个构造函数所用的顶设缓冲区大小一般就够用了。
12.5.2BufferedReader类的方法
因为BufferedReader继承了Reader类,所以它也继承了read(),read(char[]),ready(),skip()等方法,但它还有一个很特别的方法:
publicStringreadLine()throwsIOException
从数据流读取一行文字,如果已经没有数据,则返回null。
所谓一行文字即是指以’\r’或’\n’为结尾的字符串,但这个方法只会返回前面字符串的部分,而不会把’\r’和’\n’也返回去。
【例12-4】现在我们就来看一个FileReader与BufferedReader搭配使用的实例。
importjava.awt.*;
importjava.io.*;
publicclassBufferedReaderTestextendsFrame{
publicstaticvoidmain(Stringargs[]){
Stringstr;
BufferedReaderTestTest=newBufferedReaderTest();
TextAreaTa=newTextArea();
try{
//建立一个BufferedReader组件
BufferedReaderbreader=newBufferedReader
(newFileReader("c:
\\BufferedReaderTest.java"));
while(true){
str=breader.readLine();//读取一行文字
if(str==null)//读到文件结尾
break;
Ta.append(str+"\n");
}
}
catch(Exceptione){//拦截任何异常
//判断e是否为FileNotFoundException
if(e.getClass().getName().compareTo("java.io.FileNotFoundException")==0)
Ta.append("文件不存在");
else
Ta.append("读取错误");
}
Test.add(Ta,BorderLayout.CENTER);
Test.setSize(500,200);
Test.setVisible(true);
}
}
运行结果如图12-2所示:
图12-2BufferedReader类的使用
这个实例会将您c盘根目录下的BufferedReaderTest.java文件的内容一行一行读进来,并且列在TextArea里面。
如果文件不存在,则会列出“文件不存在”的错误信息,如果在读取过程中发生其它的IO错误,则会列出“读取错误”的错误信息。
因为第10行BufferedReader的构造函数会产生FileNotFoundException,而第12行会产生IOException,如果不想写两个catch分别去拦截这两个异常,也可以像第18行一样直接拦截它们的父类Exception,然后在第20行再去判断它到底是FileNotFoundException还是IOException。
【例12-5】同样的程序我们也可以用输入数据流的方式改写成如下:
importjava.awt.*;
importjava.io.*;
publicclassBufferedInputStreamTestextendsFrame{
publicstaticvoidmain(Stringargs[]){
bytestr[]=newbyte[10];//配置数组
intlen;
BufferedInputStreamTestTest=newBufferedInputStreamTest();
TextAreaTa=newTextArea();
try{
//建立一个BufferedInputStream组件
BufferedInputStreambinstream=newBufferedInputStream(newFileInputStream("c:
\\BufferedInputStreamTest.java"));
while(binstream.available()>0){//检查是否还有字符未读
len=binstream.read(str);//读取10个字符
Ta.append(newString(str,0,len));//将读到的文字列在TextArea里面
}
}
catch(Exceptione){//拦截任何意外
//判断e是否为FileNotFoundExceptionif(e.getClass().getName().compareTo("java.io.FileNotFoundException")==0)
Ta.append("文件不存在");//错误信息
else
Ta.append("读取错误");//错误信息
}
Test.add(Ta,BorderLayout.CENTER);
Test.setSize(500,200);
Test.setVisible(true);
}
}
因为BufferedInputStream类别没有readLine方法可用,所以我们必须一段一段地读进来,其实直接用FileInputStream读取资料就可以了,不需要BufferedInputStream的帮忙,但这个实例只是为了让您了解BufferedInputStream和FileInputStream的用法。
在第14行的地方,便是从资料流读进10个字符(因为str的大小为10),len便会记录共读进了几个字符,所以在第15行的地方,我们只要将str数组的前1en个字符列到TextArea中即可。
12.6writer类
既然有Reader类可以从输入数据流里读取数据,当然也会有Writer类可以把数据写进输出数据流。
Writer类和Reader类一样,也是一个抽象类,所以像flush和close这种和接收数据的装置有直接相关的方法就必须留给它的子类来覆盖。
Writer类的实现如下:
publicabstractclassWriterextendsObject
常用方法有:
1.publicabstractvoidclose()throwsIOException
关闭与输出数据流的联系,但关闭之前会先调用一次flush方法。
程序结束前没有调用这个方法,则写入的数据可能会流失掉。
2.publicabstractvoidflush()throwsIOExcept