第8章输入输出技术8.1流式输入输出8.2基本输入输出流8.3文件处理类8.4对象流习题8.1流式输入输出所有的计算机程序都必须接收输入和产生输出。针对输入、输出,Java提供了丰富的类库进行相应的处理,包括从普通的流式输入输出到复杂的文件随机访问。计算机系统使用的信息都是从输入经过计算机流向输出。这种数据流动就称为流(Stream)。输入流指数据从键盘或者文件等输入设备流向计算机;输出流指数据处理结果从计算机流向屏幕或文件等输出设备。在Java中,通过java.io包提供的类来表示流,基本的输入输出流为InputStream和OutputStream。从这两个基本的输入输出流派生出面向特定处理的流,如缓冲区读写流、文件读写流等。Java定义的流如表8.1所示。表8.1Java定义的输入输出流流描述输入流输出流音频输入输出流AudioInputStreamAudioOutputStream字节数组输入输出流ByteArrayInputStreamByteArrayOutputStream文件输入输出流FileInputStreamFileOutputStream过滤器输入输出流FilterInputStreamFilterOutputStream基本输入输出流InputStreamOutputStream对象输入输出流ObjectInputStreamObjectOutputStream管道输入输出流PipedInputStreamPipedOutputStream顺序输入输出流SequenceInputStreamSequenceOutputStream字符缓冲输入输出流StringBufferInputStreamStringBufferOutputStream8.2基本输入输出流8.2.1InputStream类InputStream是抽象类,代表字节输入流的所有类的超类。这个类本身不能使用,只能通过继承它的具体类完成某些操作。它的常用方法如下:publicintavailable()throwsIOException返回流中可用的字节数。publicvoidclose()throwsIOException关闭流并释放与流相关的系统资源。用户使用完输入流时,调用这个方法。publicvoidmark(intreadlimit)throwsIOException输入流中标志当前位置。publicbooleanmarkSupported()throwsIOException测试流是否支持标志和复位。publicabstractintread()throwsIOException读取输入流中的下一个字节。publicintread(byte[]b)throwsIOException从输入流中读取字节并存储到缓冲区数组b中,返回读取的字节数,遇到文件结尾返回-1。publicintread(byte[]b,intoff,intlen)throwsIOException从输入流中读取len个字节并写入b中,位置从off开始。返回写的字节数。publicvoidreset()throwsIOException重定位到上次输入流中调用的位置。publiclongskip(longn)throwsIOException跳过输入流中n个字节,返回跳过的字节数,遇到文件结尾返回-1。8.2.2OutputStream类OutputSteam是抽象类,代表输出字节流的所有类的超类。publicvoidclose()throwsIOException关闭输出流,释放与流相关的系统资源。publicvoidflush()throwsIOException清洗输出流,使得所有缓冲区的输出字节全部写到输出设备中。publicvoidwrite(byte[]b)throwsIOException从特定字节数组b将b数组长度个字节写入输出流。publicvoidwrite(byte[]b,intoff,intlen)throwsIOException从特定字节数组b将从off开始的len个字节写入输出流。publicabstractvoidwrite(intb)throwsIOException向输出流写一个特定字节。8.2.3系统输入输出对象Java定义了两个流对象System.in和System.out,允许用户在自己的程序中直接使用。System.in对象允许用户从键盘读取数据,System.out对象可以产生屏幕输出。【例8.1】使用流对象System.in和System.out,接收用户从键盘上输入的数据并将数据输出到屏幕上。测试情况如图8.1所示。源程序代码如下://程序文件名为SystemIO.javaimportjava.io.*;publicclassSystemIO{publicstaticvoidmain(String[]args){intbytes=0;bytebuf[]=newbyte[255];System.out.println(\n请输入任意文本:);try{//接收输入字符串bytes=System.in.read(buf,0,255);System.out.println(这是你输入的文本行:);StringinStr=newString(buf,0,bytes);//输出字符串System.out.println(inStr);}catch(IOExceptione){System.out.println(e.getMessage());}}};图8.1例8.1的屏幕显示8.3文件处理类8.3.1FileInputStream类FileInputStream(文件输入流)类是用来得到文件的输入字节流。大部分方法继承于InputStream类。它的构造方法如下:FileInputStream(Filefile)通过打开一个到实际文件的链接,创建一个文件输入流,参数file是一个文件对象。FileInputStream(Stringname)通过打开一个到实际文件的链接,创建文件输入流,参数name为文件的实际路径。【例8.2】使用FileInputStream对象打开源程序文件,源文件的输出如图8.2所示。源程序代码如下://程序文件名为UseFileInputStream.javaimportjava.io.*;publicclassUseFileInputStream{publicstaticvoidmain(String[]args){bytebuf[]=newbyte[2056];try{//构造文件输入流FileInputStreamfileIn=newFileInputStream(UseFileInputStream.java);//存入缓冲bufintbytes=fileIn.read(buf,0,2056);StringinStr=newString(buf,0,bytes);//输出文件内容System.out.println(inStr);}catch(IOExceptione){System.out.println(e.getMessage());}}};图8.2输出源文件内容8.3.2FileOutputStream类FileOutputStream(文件输出流)类是将数据写入File或FileDescriptor对象的输出流。它的方法大都是从OutStream继承来的,其构造方法如下:FileOutputStream(Filefile)创建输出流写到特定的file对象。FileOutputStream(Filefile,booleanappend)以追加的方式写入file对象。FileOutputStream(FileDescriptorfdObj)创建输出文件流到fdObj对象,代表一个到实际文件的链接。FileOutputStream(Stringname)创建输出流,写到指定的name文件。FileOutputStream(Stringname,booleanappend)是否以追加的方式写到指定的name文件。【例8.3】使用FileOutputStream对象,打开一个文件,写入一行文本,然后追加一行从键盘接收的字符串(如图8.3的上部分所示),文件内容如图8.3的下部分所示。源程序代码如下://程序文件名为UseFileOutputStream.javaimportjava.io.*;publicclassUseFileOutputStream{publicstaticvoidmain(String[]args){bytebuf[]=newbyte[255];bytebufIn[]=newbyte[255];try{Stringstr=你好,这是已有的文本;buf=str.getBytes();//创建文件输出流对象FileOutputStreamfileOut=newFileOutputStream(Hello.txt);//写入文件fileOut.write(buf,0,buf.length);fileOut.flush();fileOut.close();System.out.println(\n请输入一行文本:);//从键盘接收文本intbytes=System.in.read(bufIn,0,255);//追加文本fileOut=newFileOutputStream(Hello.txt,true);fileOut.write(bufIn,0,bytes);}catch(IOExceptione){System.out.println(e.getMessage());}}};图8.3程序运行和写入的文件内容8.3.3File类用户接口和操作系统使用依赖于系统的路径字符串来命名文件和目录。File类就表示这些文件和目录路径,它代表一个抽象的依赖于系统的层次路径视图。File类允许用户向系统查询该文件的所有信息,也可以使用类来创建新的目录或者删除和重命名文件。当用户需要获得有关文件的信息时,就需要创建一个File类,而当File类用于文件读写时,通常与FileInputStream流相结合。【例8.4】创建一个临时文件,写入一行数据,然后删除。临时文件的周期说明如图8.4所示。源程序代码如下://程序文件名为UseFile.javaimportjava.io.*;publicclassUseFile{publicstaticvoidmain(String[]args){try{Filef=newFile(temp.txt);System.out.println(创建临时文件);FileOutputStreamfout=newFileOutputStream(f);PrintStreamp=newPrintStream(fout);p.println(将这句话放入临时文件);System.out.println(写临时文件);f.deleteOnExit();System.out.println(删除临时文件);}catch(IOExceptione){System.out.println(e.getMessage());}}};图8.4临时文件的周期说明8.3.4RandomAccessFile类RandomAccessFile(随机访问文件)类的实例支持对随机访问文件的读/写。随机访问文件就像存储在文件系统中的巨大的字节数组,通过游标或者索引(叫做文件指示器)指向这个暗含的数组,输入操作从指示器处读取字节,然后前进指针。如果随机访问文件以可读/写模式创建,那么还支持输出操作,输出操作写到暗含数组的尾端,使得数组得以扩展。【例8.5】随机访问文件,将文件内容输出,并写入两个字符“O”、“K”。文件内容显示如图8.5的下半部分所示,若文件内容直接输出到屏幕上,则出现如图8.5上半部分所示的乱码问题,添加一个parseChinese方法后,得以修正,输出结果如