第20讲 Java的输入与输出流(上) 1/
教学目标 理解Java中流的概念 掌握字节流InputStream和OutputStream及其子类的使用 掌握字符流Reader和Writer及其子类的使用 掌握随机读写文件流RandomAccessFile的使用
本实例中主要应用Java的输入输出流实现文件的复制。 引例 本实例中主要应用Java的输入输出流实现文件的复制。 import java.io.*; public class Ex11_1{ public static void main(String args[]){ try{ System.out.println("创建文件输入流对象……"); FileInputStream fis=new FileInputStream("input.txt"); System.out.println("指定输入文件对象……"); byte data[]=new byte[100]; System.out.println("读入文件数据到指定数组中……"); fis.read(data); String str=data.toString(); System.out.println("创建文件输出流对象……"); FileOutputStream fos=new FileOutputStream("output.txt"); System.out.println("将指定数组的内容读入文件中……"); fos.write(str.getBytes()); System.out.println("关闭所有文件"); fis.close(); fos.close(); } catch(Exception e){ } }}
概述 源 输入流 输入流从源中读出数据 目的地 输出流 输出流向目的地中写入数据 在Java API中,I/O包提供了大量的流类来实现数据的输入和输出,主要分为两类:一种是字节流,另一种是字符流,分别由四个抽象类来表示:InputStream、OutputStream、Reader和Writer.所有输入流类都是InputStream类或者Reader类的子类,它们都继承了read()方法用于读取数据。而所有输出流类都是OutputStream类或者Writer类的子类,它们都继承了write()方法用于写入数据。
InputStream/OutputStream和Reader/Writer都直接继承自Java的根类Object,它们各自形成一个独立的继承体系。
字节流 字节流用来读写8位的数据。由于在读写中不会对数据作任何转换,所以可以用来直接处理二进制的数据。 字节流分为输入流InputStream和输出流OutputStream,所有其他的字节流都是它们的子类。
字节输入流InputStream 成员方法 主要功能 public abstract int read() throws IOException 自输入流中读取一个字节 public int read(byte b[]) throws IOException 将输入的数据存放在指定的字节数组 public int read(byte b[],int offset,int len) throws IOException 自输入流中的offset位置开始读取len个字节并存放在指定的数组b中 public void reset() throws IOException 将读取位置移至输入流标记之处 public long skip(long n) throws IOException 从输入流中跳过n个字节 public int available()throws IOException 返回输入流中的可用字节个数 public void mark(int readlimit) 在输入流当前位置加上标记 public boolean markSupported() 测试输入流是否支持标记(mark)用的所有资源 public void close()throws IOException 关闭输入流, 并释放占用的所有资源
字节输出流OutputStream类 成员方法 主要功能 public abstract void write(int b) throws IOException 写一个字节 public void write(byte b[])throws IOException 写一个字节数组 public void write (byte b[],int offset,int len) throws IOException 将字节数组b中从offset位置开始的、长度为len个字节的数据写到输出流中 public void flush() throws IOException 写缓冲区内的所有数据 public void close() throws IOException 关闭输出流,并释放占用的所有资源
标准输入流 标准输入: InputStream is=System.in; 它是一个标准输入流,一般接收键盘的响应,得到键盘所传递来的信息。
例11.2下面程序可以从键盘输入字符到程序中,并在屏幕上重新打印出来。 import java.io.*; class Ex11_2{ public static void main(String args[ ]) throws IOException { byte buf [ ] = new byte[255]; System.out.println("enter: "); System.in.read(buf, 0, 255); System.out.println("Got : "); String str = new String(buf); System.out.println(str); } }
例11.3 编程实现从键盘读入若干字符,然后显示出来。 import java.io.*; public class Ex11_3 { public static void main (String args[ ]) throws IOException { int b; while ((b = System.in.read( ) ) != -1) { System.out.print((char)b); } System.out.println( );
文件字节输入流类FileInputStream InputStream类和OutputStream类都是抽象类,不能实例化,因此在实际应用中并不使用这两个类,而是使用一些基本数据流类,如FileInputStream和FileOutputStream,它们分别是InputStream类和OutputStream类的子类,用于进行文件输入和输出的处理,其数据源和目标都是文件。 FileInputStream用于顺序访问本地文件。它从超类InputStream中继承了read、close等方法对本机上的文件进行操作,但不支持mark方法和reset方法。
FileInputStream类构造方法 FileInputStream(String name) FileInputStream(File file) FileInputStream(FileDescriptor fd) 第一个构造方法使用给定的文件名name创建一个FileInputStream对象,用来打开一个到达该文件的输入流,这个文件就是源。 第二个构造方法使用File对象FileInputStream对象,用来指定要打开哪个文件。 FileDescriptor也是java.io包中的类,主要用于关联到已打开的文件,或已打开的网络链接,或者其他I/O连接,在机器底层发挥作用,可以强制系统缓冲区与底层设备保持同步,从而为输入输出流提供一个与底层设备同步的系统缓冲区,但是这个类不大常用,大家只要了解就可以了。
FileInputStream类读取字节的方法 在创建文件输入流对象之后,可以调用read方法从流中读取字节,read方法有三种格式: public int read() throws IOException public int read(byte[] b,int off,int len) throws IOException public int read(byte[] b) throws IOException read()方法将返回一个整数,它包含了流中的下一个字节。如果返回的是-1,则表示到达了文件输入流的末尾。这种方法每次只能从文件输入流中读取一个字节,为了能从流中读入多个数据字节,可以调用read(byte b[],int off,int len)方法,该方法从输入流当前字节处起读取长度为len字节的数据,从位置off处起存入数组b中,b中位置在 off之前和在off+len之后的数据将保持不变,返回读取的数据长度,并将第len个字节设为当前字节。
FileInputStream举例 String str=""; FileInputStream fin=new FileInputStream("c:\\Ex11_3.java"); for(int i=fin.read();i!=-1;i=fin.read()) str+=(char)i; 上述程序段的功能是应用read()方法将c:\Ex11_3.java的内容输出到字符串str中。 在使用FileInputStream类时要注意: 若关联的目录或者文件不存在,Java就会抛出一个IOException异常。程序可以使用try-catch块检测和处理捕捉到的异常。例如,为了把一个文件输入流对象与一个文件关联起来,可以使用下列的代码段来处理Java产生的IOEception异常。 try{ FileInputStream fis=new FileInputStream("java7.txt"); ...... }catch(IOException e){ System.out.println("File Exception:"+e); }
关闭输入流 public void close() throws IOException 虽然Java在程序结束时会自动关闭所有打开的流,但还是建议大家养成一个良好的习惯,在使用完流后,调用close()方法显式地关闭任何打开的流,以防止一个被打开的流用完系统资源。
文件字节输出流类FileOutputStream FileOutputStream类用于向一个文本文件写数据,它从其超类OutputStream中继承了write、close等方法。 构造方法 public FileOutputStream(String name)throws FileNotFoundException public FileOutputStream(File file)throws FileNotFoundException public FileOutputStream(String name,boolean append)throws FileNotFoundException append表示文件是否为添加的写入方式。当append值false时,为重写方式,即从头写入;当append值为true时,为添加方式,即从尾写入。append默认值为false。 例如: FileOutputStream fos=new FileOutputStream("OutputFile.txt",true);
FileOutputStream类写入字节的方法 使用write方法将指定的字节写入文件输出流。Write方法有3种格式: public void write(int b)throws IOException public void write(byte[] b) throws IOException public void write(byte[] b,int off,int len) throws IOException write方法可以向文件写入一个字节、一个字节数组或一个字节数组的一部分。 当b是int类型时,b占用4个字节32位,通常是把b的低8位写入输出流,忽略其余高24位。 当b是字节数组时,可以写入从off位置开始的len个字节,如果没有off和len参数,则写入所有字节,相当于write(b,0,b.length)。
关闭输出流 public void close() throws IOException close方法关闭输出流,并释放相关的系统资源。 发生I/O错或文件关闭时,抛出IOException异常。如果off或len为负数或off+len大于数组b的长度length,则抛出IndexOutOfBoundsException异常;如果b是空数组,则抛出NullPointerException异常。 用FileOutputStream对象写入时,如果文件不存在,则会创建一个新文件,如果文件已存在,使用重写方式 则会覆盖原有数据。
例11.4 编写程序,应用FileInputStream类实现从"c:\file.dat"中读出第5个字节到变量c中,并输出。 import java.io.*; public class Ex11_4 { public static void main(String args[]){ try{ FileInputStream fis=new FileInputStream("c:\\file.dat"); fis.skip(4); int c=fis.read(); System.out.println((char)c); fis.close(); }catch(Exception e){ e.printStackTrace(); } } }
内存的读写 在java.io中,还提供了ByteArrayInputStream和ByteArrayOutputStream类来直接访问内存,它们分别是InputStream和OutputStream的子类。 类ByteArrayInputStream有两个构造方法: public ByteArrayInputStream(byte b[]) public ByteArrayInputStream(byte b[],int off,int len) 第一个构造方法以一个字节数组作为参数, 数据源完全复制到内部缓冲区。第二个构造方法的参数包括一个字节数组、一个整型偏移量和一个整型长度,与第一个构造方法不同的是,此构造方法生成的内部缓冲区将以指定偏移量位置为起始位置,并且能读取的最大数据长度为指定的长度。这个字节数组就是该输入流的数据源。内存缓冲区保持一个标记,指向当前字节。
ByteArrayInputStream类 ByteArrayInputStream可从字节数组中读取数据,它重写了其父类InputStream的部分方法,如: public int read(); public int read(byte b[],int off,int len); public long skip(long n) public int available(); public boolean markSupported(); public void mark(int tag); public void reset(); public void close() throws IOException
ByteArrayOutputStream 类 与ByteArrayInputStream对应,ByteArrayOutputStream对象中同样有一个字节数组类型的属性,作为内部缓冲区,同时也是该输出流的接收端。 类ByteArrayOutputStream有两个构造方法: public ByteArrayOutputStream() public ByteArrayOutputStream(int len ) 第一个构造方法没有参数,生成的内部缓冲区的默认大小为32个字节。第二个构造方法有一个整型参数,指定生成的内部缓冲区的初始大小,内部缓冲区大小将随数据的写入自动更改。
ByteArrayOutputStream类(续) ByteArrayOutputStream可向字节数组写入数据,它重写了其父类OutputStream的方法,如: public void write(int b); public void write(byte b[],int off,int len); public void wtiteTo(OutputStream out) throws IOException; public void reset(); public void close() throws IOException; ByteArrayOutputStream除了重写父类OutputStream以上的方法外,还自包含了以下四个方法: public byte[] toByteArray():建立一个新的数组,将缓冲区的数据复制到该数组中,并返回存放当前输出流内容的数组。 public int size():返回缓冲区的大小。 public String toString():根据操作系统默认的编码格式,将内部缓冲区的数据转换为一个字符串返回。 public String toString(String enc):根据编码格式enc,将内部缓冲区的数据转换为一个字符返回。