流和文件
輸入和輸出技術並不那麼令人興奮,如果沒有讀寫數據的能力,編寫出來的程序會受到很大的限制。
一、流
輸入流:一個可以讀取字節序列的對象被稱爲輸入流(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)