流和文件

     输入和输出技术并不那么令人兴奋,如果没有读写数据的能力,编写出来的程序会受到很大的限制。

一、流

输入流:一个可以读取字节序列的对象被称为输入流(input stream)。

输出流:一个可以写入字节序列的对象被称为输出流(output stream)。

在抽象类InputStream和OutputStream中对他们进行了说明,初次之外,由

于以字节为单位的流处理存储为Unicode码的信息很不方便,所以有一个专门的类层次来处理Unicode字符,这些类继承于抽象类Reader和Writer。它们的读写操作都是基于双字节的Unicode代码单元,而不是基于单字节。

这4种抽象类派生的具体类组成了一个Java“动物园”。在这个动物园中几乎可以看到各种像得到的输入/输出“动物”。

API  java.io.InputStream 1.0
Abstract int read()
Int read (byte[] b)
Int read (byte[]b ,int off, int len)
Long skip(long n)
Int available()
Void close ()
Void mark(int readlimit)
Void reset()
Boolean markSupported()
        API  java.io.OutputStream 1.0
Abstract void write(int n)
Void write(byte[] b)
Void close()
Void flush()
Reader和Writer类的基本方法和InputStream以及OutputStream类非常类似。
       Abstract int read()
       Abstract void write(int b)
二、常用的流
1、字节流
inputStream---------à FilterInputStream------àDataInputStream
outputStream-----àFilterOutputStream----àDataOutputStream
DataInputStream和DataOutputStream能够读写所有的基本的Java类型。
DataInputStream实现了 DataInput 接口:
             API   java.io.DataInput 1.0
Boolean readBoolean()
Byte readByte()
Double readDouble()
Float readFloat()
Int readInt()
String readUTF()
     DataOutputStream 实现了DataOutput 接口:
             API   java.io.DataOutput 1.0
Void writeBoolean(Boolean b)
Void writeByte(byte b)
Void writeDouble(double d)
Void writeInt(int  i);
Void writeUTF(String s);
    
inputStream---------à FileInputStream
outputStream-----àFileOutputStream
FileInputStream和FileOutputStream能够把输入和输出流与磁盘文件关联起来。
例:FileInputStream fin = new FileInputStream(“employee.dat”);
将在当前路径下寻找名为“employee.dat”的文件。
    例:FileInputStream fin = new FileInputStream(“C://yuyifan//employee.dat”);
例:FileInputStream fin = new FileInputStream(“C:/yuyifan/employee.dat”);
例:File f = new File(“employee.dat”);
    FileInputStream fin = new FileInputStream(f);
FileInputStream没有读取数值类型的方法一样,DataInputStream也没有从文件中读取数值的方法。
Java使用了一种很聪明的策略来划分这两种职责。一些流可以从文件及其其他地方接受字节,另一些流可以将字节组合成更加有用的数据类型。
Java程序员采用将一种已经存在的流传递给另一个流的构造器方法,将这两种流结合起来,结合后的流被称为过滤流。
例:FileInputStream fin = new FileInputStream(“employee.dat”);
    DataInputStream din = new DataInputStream(fin);
    Double s =din.readDouble();
inputStream---------à FilterInputStream------àBufferedInputStream
outputStream-----àFilterOutputStream----àBufferedOutputStream
在默认情况下,流是不能进行缓冲处理的。换句话说,每次对流进行read读取都要求操作系统发送一个字节。所以——————————:
例:DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream(“employee.dat”)));
inputStream---------à FilterInputStream------àInflaterInputStream---àZipInputStream
outputStream-----àFilterOutputStream----àInflaterOutputStream--àZipOutputSteam
例:ZipnputStream zin = new ZipInputStream(new FileInputStream(“employee.zip”));
     DataInputStream din = new DataInputStream(zin);
RandomAccessFile流类能够在文件的任何位置查找或者写入数据,它同时实现了DataInput和DataOutput接口。打开一个随机存取文件,要么进行只读操作,要么进行读写操作。
例:RandomAccessFile in = new RandomAccessFile(“employee.dat”,”r”);
    RandomAccessFile inout = new RandomAccessFile(“employee.dat”,”rw”);
随机存取文件同时提供了一个文件指针。文件指针总是指向下一条要进行读写操作记录的位置。Seek方法将文件指针设定在文件内部的任意字节位置。getFilePointer方法返回的是文件指针的当前位置。
        API  java.io.RandomAccessFile 1.0
RandomAccessFile(String file ,String mode)
RandomAccessFile(File file, String mode);
Long getFilePointer()
Void seek(long pos)
Long length()
2、文本流
   Read ----àInputStreamReader-àFileReader
   Writer--àOutputSteamWriter--àFileWriter
   重点:文本文件的I/O
   例:InputStreamReader    in = new InputStreamReader(System.in);
       InputStreamReader in = new InputStreamReader(new FileInputStream(“yyf.dat”),”ISO8859_5”);
      
      FileWriter out = new FileWriter(“output.txt”);
      相当于
      FileWriter out = new FileWriter(new FileOutputStream(“output.txt”));
  进行文本输出时,应该使用PrintWriter. PrintWriter可以以文本格式打印字符串和数值。 一个PrintWriter必须与一个目标writer相结合。
  例:PrintWriter out = new PrintWriter(new FileWriter(“employee.txt”));
  例:PrintWriter out = new PrintWriter(new FileOutputStream(“employee.txt”));
  代码片断:
      String name = “YYf”;
      Double salary = 6700;
      Out.print(name);
      Out.print(‘ ’);
      Out.println(“salary”);
  例:PrintWriter out = new PrintWriter(new FileWriter(“employee.txt”),true);
    
   如果writer被设为自动刷新模式,任何时候调用println,缓冲区内的所有字符都会被送到其目的地。(printwriter 总是缓冲的。) 默认情况下,自动刷新不开启。
在JDK5.0以前,唯一用来处理文本输入的是BufferedReader,在这个类中有一个readLine()方法,它能以行的方式读取文本,并需要将一个缓冲的读取器同一个输入源接合起来。
例:  BufferedReader in = new BufferedRead(new FileReader(“employee.txt”));
      String line ;
      While( (line = in.readLine()) ! =null)
{
 //Do something with line
}
Zip文件流
   Zip文件(通常)以压缩格式存储一个或更多文件。Java1.1可以处理GZIP和ZIP格式。
  注意: 处理ZIP文件的类在java.util.zip中而不在java.io中,所以请记住要添加必要的import语句。尽管不是java.io的一部分,但GZIP和ZIP类还是java.io.FilterInputStream和java.io.FilterOutputStream的子类。
  每个ZIP文件都有文件头,其中包括了诸如文件名和使用的压缩方法等信息。
代码片断:
  ZipInputStream zin = new ZipInputStream(new FileInputStream(zipname));
  ZipEntry entry;
  While((entry = zin.getNextEntry())!=null)
{
  // 分析 entry
   //读 zin 的内容
   //Zin.closeEntry();
}
Zin.close();
看例子 :打开一个ZIP文件。然后再屏幕的顶部的一个复合框中显示出ZIP压缩文件中存在的所有文件。如果双击其中一个文件,该文件的内容就会在文本区显示出来。例子 ZipTest.java.
        API  java.util.zip.ZipInputStream1.1
ZipInputStream(InputStream in)
这个构造器创建一个ZipInputStream,它允许从给定的InputStream内读取数据。
ZipEntry  getNextEntry()
返回下一条目的ZipEntry对象;如果没有更多的条目的话,返回null。
Void closeEntry()
关闭ZIP文件中当前打开的条目。随后可以使用getNextEntry()读取下一条目。
        API   java.util.zip.ZipOutputStream 1.1
ZipOutputStream(OutputStream out)
这个构造器创建了一个ZipOutputStream,使用它可以向指定的OutputStream内写入压缩数据。
Void   putNextEntry(ZipEntry ze)
将给定的ZipEntry的信息写入流中,并且为数据定位流。随后可以使用write()把数据写入流中。
 Void closeEntry()
关闭ZIP文件中当前打开的条目。随后可以使用putNextEntry()方法开始对下一条目进行操作。
        API  java.util.zip.ZipEntry 1.1
ZipEntry(String name)
构造一个压缩条目。
String getName()
返回该条目的名称。
Long getSize()
返回该条目未经压缩时的大小;如果未经压缩时的大小未知,返回-1。
Boolean isDirectory()
返回一个布尔值表明该条目是否为一个目录。
流的使用样例:
1、将相同类型的多个对象中的实例变量保存的值以文本格式保存。
文件: DataFileTest.java 
        API   java.util.StringTokenizer 1.0
StringTokenizer(String str ,String delim)
使用给定的分隔符集合构造一个字符串的记号处理器。
StringTokenizer(String str )
构造一个字符串的记号处理器,使用默认的分隔符集“/t/n/r”
String hasMoreToken()
如果存在更多的记号则返回true.
String nextToken()
返回下一个记号,如果没有记号,则抛出一个NoSuchElementException异常。
String nextToken(String delim)
在切换到新的分隔符集后,返回下一个记号,以后使用新的分隔符集。
Int countTokens()
返回在字符串中的记号个数。
样例输出:
Harry Hacker | 35500|1989|10|1
Carl Cracker|75000|1987|12|15
Tony Tester|38000|1990|3|15
2、将相同类型的多个对象中的实例变量保存的值以二进制格式保存。
用RandomAccessFile类。
样例文件:RandomFileTest.java
3、将多个对象以对象的形式保存。
样例文件:ObjectFileTest.java
注意:所有要写入文件的对象都要实现Serializable接口。
        API    java.io.ObjectOutputStream
ObjectOutputStream(OutputStream out)
Void writeObject(Object obj)
        API   java.io.ObjectInputStream
ObjectInputStream(InputStream in)
Void readObject(Object obj)