java核心课件-第13章.ppt
第13章 I/O流,熟练使用File类的常用方法;理解流,及其层次结构;能熟练使用字节流和字符流类对文件进行读写操作。,31.1 File类,File f=new File(my.txt);f.createNewFile();f.mkdir();File f=new File(F:myjavaclass81.txt);f.createNewFile();File fDir=new File(File.separator+myjavaclass8);String strFile=File.separator+“1.txt;File f=new File(fDir,strFile);f.createNewFile();File arrFile=f.listFiles();File arrFile=f.listFiles(new Test();public boolean accept(File dir,String name)return name.indexOf(.java)!=-1;,13.2 流的概念,流是程序和外界进行数据交换的通道;它是一种抽象观念,如从键盘输入数据、将结果输出到显示器、打开与保存文件等操作皆视为流的处理。我们可通过它来读写数据,甚至可以通过它连接数据来源(data source),并可以将数据保存。使用流的好处是:能非常灵活地在文件中保存数据或从文件中读取数据。,stream(流),流是指一连串流动的数据信号,是以先进先出的方式发送和接收数据的通道。,InputStream,来自数据源的数据流,OutputStream,流向目的地的数据流,流(续),13.3 流相关类的层次结构,Java有一套完整的输入/输出类层次结构,它们是建立在4个抽象类的基础上的;Java中的流主要有字节流和字符流。,流的类型,根据流动方向的不同,流分为输入流和输出流;对于输入和输出流,由于传输格式的不同,又分为字节流和字符流:字节流是指8位的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于InputStream(输入字节流)类和OutputStream(输出字节流)类;字符流是指16位的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于Reader(读取流)类和Writer(写入流)类。,字节输入输出流层次,字符输入输出流层次,13.4 字节流,不管是输入流还是输出流,用完以后都必须关闭,且应放在finally子句中;读写操作都会抛异常,必须进行处理;汉字最好用字符流操作。,13.4.3 文件输入/输出流,import java.io.*;class StreamTest public static void main(String args)throws IOException FileInputStream fis=new FileInputStream(1.txt);byte buf=new byte1024;int len=fis.read(buf);System.out.println(new String(buf,0,len);fis.close();FileOutputStream fos=new FileOutputStream(1.txt);fos.write(aaj;akajaa;pvzoi.getBytes();fos.close();,其构造方法参数中的字符串可以是路径也可以是文件名,13.4.5 连接字节输入流,import java.io.*;public class SequenceTest public static void main(String args)throws IOException FileInputStream fis1=new FileInputStream(1.txt);FileInputStream fis2=new FileInputStream(2.txt);SequenceInputStream sis=new SequenceInputStream(fis2,fis1);byte buf=new byte1024;int len1=sis.read(buf);int len2=sis.read(buf,len1,1024-len1);System.out.println(new String(buf,0,len1+len2);sis.close();,当有多个流连接在一起时,关闭最外层流就可以了,13.4.6 过滤字节流,它本身不是流,是一种用于扩展底层流功能的装饰器,它的子类,分别用来扩展字节流的某一种功能;它必须先创建对应字节流对象,再以它为参数来创建过滤字节流类的象,然后利用此对象扩展字节流的功能,就像把字节流包覆于其中;关闭文件时,一般只关闭外层流即可。,13.4.6.1 缓冲输入/输出流,BufferedInputStream的特点是:不断的从底层流中读取数据,可以减少I/O请求次数,提高效率;BufferedInputStream的特点是:先将数据写到缓冲里,缓冲满后再一次性写入,可以减少I/O请求次数,提高效率;一般在关闭前调用flush方法,将数据强制写入。,import java.io.*;class StreamTest public static void main(String args)throws IOException FileInputStream fis=new FileInputStream(1.txt);BufferedInputStream bis=new BufferedInputStream(fis);byte buf=new byte1024;int len=bis.read(buf);System.out.println(new String(buf,0,100);bis.close();FileOutputStream fos=new FileOutputStream(1.txt);BufferedOutputStream bos=new BufferedOutputStream(fos);bos.write(aaj;akajaa;pvzoi.getBytes();bos.flush();bos.close();,13.4.6.2 格式化输出流,PrintStream类的特点是:可以直接写基本数据类型和字符串;可指定自动刷新缓存;方法不会抛出异常标准类库中System等类都使用了它;,import java.io.*;class StreamTest public static void main(String args)throws IOException FileOutputStream fos=new FileOutputStream(1.txt);BufferedOutputStream bos=new BufferedOutputStream(fos);PrintStream ps=new PrintStream(fos,true);ps.print(aaj;akajaa;pvzoi);ps.close();,13.4.6.3 数据输入/输出流,DataInput接口抽象出来的行为是:从二进制流中读取字节,并根据Java基本数据类型进行重构;DataOutput接口抽象出来的行为是:将数据从任意Java基本数据类型转换为一系列字节,并将这些字节写入字节流;DataInputStream和DataOutputStream分别实现了这两个接口;DataOutputStream的特点是:可以写基本数据类型;DataInputStream的特点是:可以读基本数据类型,读时文件到尾不会返回-1,而是抛出异常;因此,这两种流通常成对使用,否则容易发生异常;用这两种流时,读写的顺序应相同,否则读出的数据不对。,import java.io.*;class StreamTest public static void main(String args)throws IOException FileOutputStream fos=new FileOutputStream(1.txt);BufferedOutputStream bos=new BufferedOutputStream(fos);DataOutputStream dos=new DataOutputStream(bos);byte b=3;int i=78;char ch=a;float f=4.5f;dos.writeByte(b);dos.writeInt(i);dos.writeChar(ch);dos.writeFloat(f);dos.flush();dos.close();FileInputStream fis=new FileInputStream(1.txt);BufferedInputStream bis=new BufferedInputStream(fis);DataInputStream dis=new DataInputStream(bis);System.out.println(dis.readByte();System.out.println(dis.readInt();System.out.println(dis.readChar();System.out.println(dis.readFloat();dis.close();,13.4.6.11自定义流,import java.io.*;class MyOutputStream extends FilterOutputStream MyOutputStream(OutputStream out)super(out);public void write(int x)throws IOException super.write(x+10);,自定义输出流时,一般只覆盖一个write方法:write(int x),因为在内部,别的write方法都调用它;注意:方法要抛出异常,import java.io.*;class MyInputStream extends FilterInputStream MyInputStream(InputStream in)super(in);public int read()throws IOException int x=super.read();return(x=-1)?-1:(x-10);public int read(byte b,int offset,int len)throws IOException int x=super.read(b,offset,len);for(int i=offset;i(offset+x);i+)bi=(byte)(bi-10);return x;,自定义输入流时需要覆盖两个方法:read()和read(byte b,int offset,int len),测试自定义流,import java.io.*;class StreamTest public static void main(String args)throws IOException FileOutputStream fos=new FileOutputStream(1.txt);MyOutputStream mos=new MyOutputStream(fos);mos.write(aaj;akajaa;pvzoi.getBytes();mos.flush();mos.close();FileInputStream fis=new FileInputStream(1.txt);MyInputStream mis=new MyInputStream(fis);byte buf=new byte1024;int len=mis.read(buf);System.out.println(new String(buf,0,100);mis.close();,13.4.7 对象序列化,对象序列化就是将对象某一时刻的状态保存到外部的存储介质上;对象序列化的功能:可以将程序运行时的某个状态保存到外部存储介质上,可以很好的完成对象深克隆;将序列化的对象读取出来叫反序列化;注意接口中方法抛出的异常;序列化时,一般扩展FileOutputStream和 FileInputStream。,13.4.7.5 对象序列化的实现方法,import java.io.*;class Employee implements Serializable String name;int age;double salary;Employee(String name,int age,double salary)this.name=name;this.age=age;this.salary=salary;,最简单的实现方法:声明实现Serializable接口;该接口是标记性接口,没有任何方法,只声明就可以了;这种方式实现的序列化时默认序列化行为;,class ObjectSerialTest public static void main(String args)throws IOException,ClassNotFoundException Employee e1=new Employee(zhangsan,25,3000);Employee e2=new Employee(lisi,24,3200);Employee e3=new Employee(wangwu,27,3800);FileOutputStream fos=new FileOutputStream(employee.txt);ObjectOutputStream oos=new ObjectOutputStream(fos);oos.writeObject(e1);oos.writeObject(e2);oos.writeObject(e3);oos.close();FileInputStream fis=new FileInputStream(employee.txt);ObjectInputStream ois=new ObjectInputStream(fis);Employee e;for(int i=0;i3;i+)e=(Employee)ois.readObject();System.out.println(e.name+:+e.age+:+e.salary);ois.close();,虽然Serializable接口中没有任何方法,但必须声明实现它才能序列化,否则运行时会抛异常反序列化的read方法返回的是Object的对象,需要强转为当前类的对象;子类继承父类时,如果父类没有实现序列化,而子类实现了,那么反序列化时要求父类有无参构造方法;子类继承父类时,如果父类实现序列化,而子类没有实现,则均可序列化;可持久化的数据才能序列化,不能序列化或不想序列化的数据可以用transient声明。,二、在要实现序列化的类中提供两个私有方法根据需要给出自己想要的序列化方法;序列化和反序列化时会分别调用它们。,private void writeObject(ObjectOutputStream oos)throws IOExceptionoos.writeInt(age);oos.writeObject(name);private void readObject(ObjectInputStream ois)throws IOException,ClassNotFoundException age=ois.readInt();name=(String)ois.readObject();,三、实现Externalizable接口,import java.io.*;class Employee implements Externalizable String name;int age;double salary;public Employee()Employee(String name,int age,double salary)this.name=name;this.age=age;this.salary=salary;public void writeExternal(ObjectOutput oo)throws IOExceptionoo.writeInt(age);oo.writeObject(name);public void readExternal(ObjectInput oi)throws IOException,ClassNotFoundException age=oi.readInt();name=(String)oi.readObject();,该接口接中的两个方法,实参可传实现了ObjectInput和ObjectOutput接口的类的对象,因此ObjectInputStream和ObjectOutputStream的方法均可在它们中使用;类中必须有公有的无参构造方法;Serializable接口序列化一个对象时,有关类的信息,比如它的属性和这些属性的类型,都与实例数据一起被存储起来;在选择走Externalizable这条路时,Java 只存储有关每个被存储类型的非常少的信息;如果两个接口都声明实现了,系统选择走Externalizable这条路。,13.6 字符流,字符流:一次I/O请求读取一个字符,可用于读写纯文本文件;字符流都带同步锁;字符流的最底层实际就是字节流,它们之间的转换用桥接器。常用的四个桥接器:InputStreamReader、OutputStreamWriter、FileReader、FileWriter,13.6.1 字符输入/输出流,import java.io.*;class StreamTest public static void main(String args)throws IOException FileReader fr=new FileReader(2.txt);char ch=new char1024;int len=fr.read(ch);System.out.println(new String(ch,0,len);fr.close();FileWriter fw=new FileWriter(2.txt);fw.write(haoanoz我们+n+zoaljva);fw.close();,13.6.2 缓存字符输入/输出流,import java.io.*;class StreamTest public static void main(String args)throws IOException FileReader fr=new FileReader(2.txt);BufferedReader br=new BufferedReader(fr);String str;while(str=br.readLine()!=null)System.out.println(str);br.close();FileWriter fw=new FileWriter(2.txt);PrintWriter pw=new PrintWriter(fw,true);pw.println(haoanoz他们+n+zoaljva);pw.close();,在使用BufferedReader读文件时,一般用它的readLine方法;一般用PrintWriter代替BufferedWriter;PrintWriter可以格式化输出,更灵活;且启用自动刷新后,println方法可以自动刷新缓存,文件复制,import java.io.*;class StreamTest public static void main(String args)throws IOException FileReader fr=new FileReader(2.txt);BufferedReader br=new BufferedReader(fr);FileWriter fw=new FileWriter(1.txt);PrintWriter pw=new PrintWriter(fw,true);String str;while(str=br.readLine()!=null)pw.println(str);br.close();pw.close();,文件读写GUI程序,import java.io.*;import java.awt.*;import java.awt.event.*;class FISFrameTest extends Frame implements ActionListenerPanel p1=new Panel();TextArea ta=new TextArea(,6,24,TextArea.SCROLLBARS_VERTICAL_ONLY);Button btnO=new Button(打开);Button btnS=new Button(保存);FileInputStream fis;FileOutputStream fos;FISFrameTest()super(I/O);add(p1,BorderLayout.SOUTH);add(ta);p1.add(btnO);p1.add(btnS);btnO.addActionListener(this);btnS.addActionListener(this);setSize(400,150);setLocation(100,100);addWindowListener(new WindowAdapter()public void windowClosing(WindowEvent e)System.exit(0););setVisible(true);,public void actionPerformed(ActionEvent e)if(e.getSource()=btnO)try fis=new FileInputStream(1.txt);byte buf=new byte1024;int len=fis.read(buf);ta.setText(new String(buf,0,len);catch(IOException ex)finally try fis.close();catch(IOException ex)else try fos=new FileOutputStream(1.txt);fos.write(ta.getText().getBytes();catch(IOException ex)finally try fos.close();catch(IOException ex)public static void main(String args)FISFrameTest t=new FISFrameTest();,