1、第第9章章流式输入输出与文件处理流式输入输出与文件处理 9.1 输入输出基本概念输入输出基本概念9.2 面向字节的输入输出面向字节的输入输出 9.3 面向字符的输入输出面向字符的输入输出 9.4 文件处理文件处理9.5 对象串行化对象串行化9.1.1 I/O设备与文件设备与文件 1.I/O设备分类设备分类存储设备存储设备 存储设备包括硬盘、软盘、光盘等,存储设备包括硬盘、软盘、光盘等,输入输入/输出设备输出设备 输入设备有键盘、鼠标、扫描仪等输入设备有键盘、鼠标、扫描仪等 输出设备有显示器、打印机、绘图仪等。输出设备有显示器、打印机、绘图仪等。2.文件的分类文件的分类 根据数据的组织方式分为根
2、据数据的组织方式分为 文本文件文本文件-存放的是存放的是ASCII码(或其它编码)表示的字符码(或其它编码)表示的字符 二进制文件二进制文件-具有特定结构的数据。具有特定结构的数据。9.1.2 流的概念流的概念 1.流的定义流的定义 流是在计算机的输入输出操作中流动的数据系列流是在计算机的输入输出操作中流动的数据系列 输出流是往存储介质或数据通道中写入数据输出流是往存储介质或数据通道中写入数据 输入流是从存储介质或数据通道中读取数据输入流是从存储介质或数据通道中读取数据 流的特性与分类流的特性与分类2.流的特性流的特性先进先出。先进先出。顺序存取。顺序存取。只读或只写。只读或只写。3.Java
3、流的处理分类流的处理分类面向字节的流,数据的处理是以字节为基本单位;面向字节的流,数据的处理是以字节为基本单位;面向字符的流,用于字符数据的处理。面向字符的流,用于字符数据的处理。4.Java系统预定义的流对象系统预定义的流对象 标准输入(标准输入(System.in):):InputStream类型,通常代表键盘输入;类型,通常代表键盘输入;标准输出(标准输出(System.out):):PrintStream类型,通常写往显示器;类型,通常写往显示器;标准错误输出(标准错误输出(System.err):):PrintStream类型,通常类型,通常 写往显示器。写往显示器。标准输入输出在实
4、际运行时的具体目标对象也可能变化,标准输入输出在实际运行时的具体目标对象也可能变化,System类中提供了如下方法重新设置标准流对象:类中提供了如下方法重新设置标准流对象:static void setIn(InputStream in):重新定义标准输入流:重新定义标准输入流 static void setErr(PrintStream err):重新定义标准错误输出:重新定义标准错误输出 static void setOut(PrintStream out):重新定义标准输出:重新定义标准输出 9.2 文件与目录管理文件与目录管理(1)创建一个新的文件对象创建一个新的文件对象 File(S
5、tring path)File(String path,String name)例:例:myFile=new File(/etc,motd);File(File dir,String name)(2)获取文件或目录属性获取文件或目录属性 String getName()返回文件名返回文件名 String getPath()String getAbsolutePath()String getParent()boolean exists()boolean canWrite()boolean canRead()boolean isFile()boolean isDirectory()long las
6、tModified()long length()(3)文件或目录操作文件或目录操作 boolean renameTo(File newName)boolean mkdir()String list()void delete()boolean equals(File f)例例9-1 显示若干文件的基本信息显示若干文件的基本信息import java.io.*;class fileinfo static File fileToCheck;public static void main(String args)throws IOException if(args.length0)for(int i=
7、0;i0)int lastbit=n%10;n=n/10;sum=sum+lastbit;System.out.println(x+的各位数字之和的各位数字之和=+sum);9.3.2 面向字节的输出流面向字节的输出流 2、文件输入、文件输入/输出流的使用输出流的使用类类OutputStream的方法的方法 public void write(int b):将参数:将参数b的低字节写入的低字节写入输出流输出流 public void write(byte b):将字节数组全部写:将字节数组全部写入输出流入输出流 public void flush():强制将缓冲区数据写入输出:强制将缓冲区数据
8、写入输出流对应的外设流对应的外设 public void close():关闭输出流:关闭输出流 2、文件输入、文件输入/输出流的使用输出流的使用 例例9-4 将一个大文件分拆为若干小文件将一个大文件分拆为若干小文件 import java.io.*;public class BigToSmall public static void main(String args)int number=0;final int size=Integer.parseInt(args1);byte b=new bytesize;try FileInputStream infile=new FileInputSt
9、ream(args0);while(true)FileOutputStream outfile=new FileOutputStream(file+number);number+;int byteRead=infile.read(b);if(byteRead=-1)break;outfile.write(b,0,byteRead);outfile.close();catch(IOException e)基本数据类型数据的读写问题基本数据类型数据的读写问题 类类DataOutputStream实现各种类型数据的输出处理,它实现各种类型数据的输出处理,它实现了实现了DataOutput接口接口 w
10、riteByte(int)writeBytes(String)writeBoolean(boolean)writeChars(String)writeInt(int)writeLong()writeFloat(float)writeDouble(double)writeUTF(String)等。等。例例9-5 找出找出10100之间的所有姐妹素数,写入到文之间的所有姐妹素数,写入到文件中。所谓姐妹素数是指相邻两个奇数均为素数件中。所谓姐妹素数是指相邻两个奇数均为素数 import java.io.*;public class FindSisterPrime public static bool
11、ean isPrime(int n)for(int k=2;k=Math.sqrt(n);k+)if(n%k=0)return false;return true;public static void main(String arguments)try FileOutputStream file=new FileOutputStream(x.dat);DataOutputStream out=new DataOutputStream(file);for(int n=11;n100;n+=2)if(isPrime(n)&isPrime(n+2)out.writeInt(n);out.writeI
12、nt(n+2);out.close();catch(IOException e);x.Dat文件FileOutputStreamDataOutputStream数据数据.import java.io.*;public class OutSisterPrime public static void main(String arguments)try FileInputStream file=new FileInputStream(x.dat);DataInputStream in=new DataInputStream(file);try while(true)int n1=in.readInt
13、();int n2=in.readInt();System.out.println(n1+,+n2);catch(EOFException e)in.close();catch(IOException e)9.3.3 对象输入流和对象输出流对象输入流和对象输出流 writeObject()和()和readObject()方法实现了对象的串行化方法实现了对象的串行化(Serialized)和反串行化)和反串行化(Deserialized)例例9-6 系统对象的串行化处理系统对象的串行化处理 程序程序1:将系统对象写入文件:将系统对象写入文件 import java.io.*;import jav
14、a.util.*;public class writedate public static void main(String args)try ObjectOutputStream out=new ObjectOutputStream(newFileOutputStream(storedate.dat);out.writeObject(new Date();out.writeObject(hello world);System.out.println(写入完毕写入完毕);catch(IOException e)程序程序2:读取文件中的对象并显示出来:读取文件中的对象并显示出来 import j
15、ava.io.*;import java.util.*;public class readdate public static void main(String args)try ObjectInputStream in=new ObjectInputStream(new FileInputStream(storedate.dat);Date current=(Date)in.readObject();System.out.println(日期:日期:+current);String str=(String)in.readObject();System.out.println(字符串字符串:+
16、str);catch(IOException e)catch(ClassNotFoundException e)3、用户定义类的对象串行化、用户定义类的对象串行化 例例9-7 利用对象串行化将各种图形元素以对象形式利用对象串行化将各种图形元素以对象形式存储,从而实现图形的保存。存储,从而实现图形的保存。程序程序1:图形对象的串行化设计:图形对象的串行化设计import java.awt.Graphics;abstract class Graph implements Serializable /抽象类抽象类 public abstract void draw(Graphics g);/定义定义
17、draw方法方法class Line extends Graph implements Serializable int x1,y1;int x2,y2;public void draw(Graphics g)g.drawLine(x1,y1,x2,y2);public Line(int x1,int y1,int x2,int y2)this.x1=x1;this.y1=y1;this.x2=x2;this.y2=y2;class Circle extends Graph implements Serializable int x,y;int r;public void draw(Graph
18、ics g)g.drawOval(x,y,r,r);public Circle(int x,int y,int r)this.x=x;this.y=y;this.r=r;程序程序2:测试将图形对象串行化写入文件:测试将图形对象串行化写入文件 import java.io.*;public class WriteGraph public static void main(String a)Line k1=new Line(20,20,80,80);Circle k2=new Circle(60,50,80);try ObjectOutputStream out=new ObjectOutputS
19、tream(new FileOutputStream(“storedate.dat”);out.writeObject(new Integer(2);out.writeObject(k1);out.writeObject(k2);catch(IOException e)System.out.println(e);程序程序3:对串行化图形对象的访问并绘制图形:对串行化图形对象的访问并绘制图形 import java.awt.*;import java.io.*;public class DisplayGraph extends Frame public static void main(Stri
20、ng a)new DisplayGraph();public DisplayGraph()super(读对象文件显示图形读对象文件显示图形);setSize(300,300);setVisible(true);Graphics g=getGraphics();try ObjectInputStream in=new ObjectInputStream(new FileInputStream(storedate.dat);int n=(Integer)in.readObject().intValue();for(int i=1;i=n;i+)Graph me=(Graph)in.readObje
21、ct();me.draw(g);catch(IOException e)System.out.println(e);catch(ClassNotFoundException e)System.out.println(e);调用对象的方法绘图调用对象的方法绘图9.4.1 面向字符的输入流类层次面向字符的输入流类层次 表表9-5 类类Reader的主要子类及说明的主要子类及说明 类名 构造方法的主要参数 功能描述 CharArrayReader字符数组char 用于对字符数组中的数据进行转换 BufferedReader类Reader的对象 为输入提供缓冲的功能,提高效率 LineNumberRe
22、ader 类Reader的对象 为输入数据附加行号 InputStreamReader InputStream的对象 将面向字节的输入流转换为字符输入流 表表9-3 类类Reader的主要子类及说明(续)的主要子类及说明(续)FileReader文件对象或字符串表示的文件名 文件作为输入源 PipedReaderPipedWriter的对象 与另一输出管道相连,读取另一管道写入的字符 StringReader字符串 以程序中的一字符串作为输入源,通常用于对字符串中的数据进行转换 LineNumberReader类的使用类的使用 例例9-8 从一个文本文件中读取数据加上行号后显示。从一个文本文件
23、中读取数据加上行号后显示。import java.io.*;public class AddLineNo public static void main(String args)try FileReader file=new FileReader(AddLineNo.java);LineNumberReader in=new LineNumberReader(file);boolean eof=false;while(!eof)String x=in.readLine();if(x=null)/是否读至文件尾是否读至文件尾 eof=true;else System.out.println(in
24、.getLineNumber()+:+x);in.close();catch(IOException e);例例9-8(续)(续)9.4.2 面向字符的输出流类层次面向字符的输出流类层次 表9-4 类Writer的主要子类及说明类名 构造方法的主要参数 功能描述 CharArrayWriter字符数组char 用于对字符数组中的数据进行转换 BufferedWriter类Writer的对象 为输出提供缓冲的功能,提高效率 InputStreamWriter OutputStream的对象 将面向字节的输出流转换为字符输出流 FileWriter文件对象或字符串表示的文件名 文件作为输出源 表9
25、-4 类Writer的主要子类及说明(续)PipedWriterPipedReader的对象 与另一输出管道相连,写入数据给另一管道供其读取 StringWriter字符串 以程序中的一字符串作为输出源,用于对字符数组中的数据进行转换 FilterWriterWriter的对象 装饰另一输出流以提供附加的功能 PrinterWriterWriter的对象或OutputStream的对象 为所装饰的输出流提供打印输出,与类PrintStream只有细微差别。例例9-9 用用FileWriter流将流将ASCII英文字符集字符英文字符集字符写入到文件写入到文件import java.io.*;pu
26、blic class CharWrite public static void main(String args)try FileWriter fw=new FileWriter(charset.txt);for (int i=32;i126;i+)fw.write(i);fw.close();catch(IOException e)类类Writer提供的方法与提供的方法与OutputStream类似,只是类似,只是将基于将基于Byte的参数改为基于的参数改为基于Char,FileWriter继继承承Writer类,几种常用形态如下。类,几种常用形态如下。public void write(i
27、nt c)往文件写入一个字符,它是将整数的低往文件写入一个字符,它是将整数的低16位对应位对应的数据写入文件,高的数据写入文件,高16位将忽略。位将忽略。public void write(char cbuf)将一个字符数组写入文件将一个字符数组写入文件 public void write(String str)将一个字符串写入文件将一个字符串写入文件【注意注意】第一种形式不能处理汉字,要将汉字写入第一种形式不能处理汉字,要将汉字写入文件可以使用后面两种形式。文件可以使用后面两种形式。9.5 转换流转换流 转换输入流转换输入流 InputStreamReader-在字节流和字在字节流和字符流间
28、架起了一道桥梁。符流间架起了一道桥梁。BufferedReader in=new BufferedReader(new InputStreamReader(System.in);9.5.2 转换输出流(转换输出流(OutputStreamWriter)类类OutputStreamWriter是是Writer的子类。一个的子类。一个OutputStreamWriter对象将对象将UTF-16字符转换为指定的字字符转换为指定的字符编码形式写入到字节输出流。类符编码形式写入到字节输出流。类OutputStreamWriter的的常用构造方法有:常用构造方法有:public OutputStreamW
29、riter(OutputStream out):创建转:创建转换输出流,按默认字符集的编码往输出流写数据。换输出流,按默认字符集的编码往输出流写数据。public OutputStreamWriter(OutputStream out,Charset c):创建转换输出流,按指定字符集的编码往输出流写数据。创建转换输出流,按指定字符集的编码往输出流写数据。public OutputStreamWriter(OutputStream out,String enc)throws UnsupportedEncodingException:创建转换输出:创建转换输出流,按名称所指字符集的编码往输出流写
30、数据。流,按名称所指字符集的编码往输出流写数据。9.6 随随 机机 访访 问问 文文 件件(1)创建随机访问文件创建随机访问文件用用 文文 件件 名名myRAFile=new RandomAccessFile(String name,String mode);用用 文文 件件 对对 象象myRAFile=new RandomAccessFile(File file,String mode);其中,其中,mode参数决定了访问文件的权限,如只读参数决定了访问文件的权限,如只读r或读写或读写wr等。等。(2)对文件位置指针的操作对文件位置指针的操作 可以使用在可以使用在DataInputStrea
31、m 和和DataOutputStream里出现的所有里出现的所有read()和和write()函函 数。数。还有几个函数帮助你在文件里移动指针:还有几个函数帮助你在文件里移动指针:long getFilePointer();返回当前指针返回当前指针 void seek(long pos);将文件指针定位到一个绝将文件指针定位到一个绝对地址。地址是相对于文件头的偏移量。地址对地址。地址是相对于文件头的偏移量。地址0表示文件的开头。表示文件的开头。long length();返回文件的长度。返回文件的长度。例例9-11:用随机文件记录访问计数用随机文件记录访问计数 RandomAccessFile fio=new RandomAccessFile(log.txt,rw);if(fio.length()=0)count=1L;else fio.seek(0);count=fio.readLong();count=count+1L;fio.seek(0);fio.writeLong(count);fio.close();