近期學習了Java的IO流,嘗試着總結一下。java
java.io 包下的IO流不少:數組
其中,以Stream結尾的爲字節流,以Writer或者Reader結尾的爲字符流。全部的輸入流都是抽象類IuputStream(字節輸入流)或者抽象類Reader(字符輸入流)的子類,全部的輸出流都是抽象類OutputStream(字節輸出流)或者抽象類Writer(字符輸出流)的子類。字符流能實現的功能字節流都能實現,反之不必定。如:圖片,視頻等二進制文件,只能使用字節流讀寫。安全
FileReader類 網絡
構造方法摘要 | |
---|---|
FileReader(File file) 在給定從中讀取數據的 File 的狀況下建立一個新 FileReader。 |
|
FileReader(FileDescriptor fd) 在給定從中讀取數據的 FileDescriptor 的狀況下建立一個新 FileReader。 |
|
FileReader(String fileName) 在給定從中讀取數據的文件名的狀況下建立一個新 FileReader。 |
FileWriter類多線程
構造方法摘要 | |
---|---|
FileWriter(File file) 根據給定的 File 對象構造一個 FileWriter 對象。 |
|
FileWriter(File file, boolean append) 根據給定的 File 對象構造一個 FileWriter 對象。 |
|
FileWriter(FileDescriptor fd) 構造與某個文件描述符相關聯的 FileWriter 對象。 |
|
FileWriter(String fileName) 根據給定的文件名構造一個 FileWriter 對象。 |
|
FileWriter(String fileName, boolean append) 根據給定的文件名以及指示是否附加寫入數據的 boolean 值來構造 FileWriter 對象。 |
使用FileReader和FileWriter類完成文本文件複製:app
1 import java.io.FileReader; 2 import java.io.FileWriter; 3 import java.io.IOException; 4 5 public class CopyFile { 6 public static void main(String[] args) throws IOException { 7 //建立輸入流對象 8 FileReader fr=new FileReader("C:\\Test\\copyfrom.txt");//文件不存在會拋出java.io.FileNotFoundException 9 //建立輸出流對象 10 FileWriter fw=new FileWriter("C:\\Test\\copyto.txt"); 11 /*建立輸出流作的工做: 12 * 一、調用系統資源建立了一個文件 13 * 二、建立輸出流對象 14 * 三、把輸出流對象指向文件 15 * */ 16 //文本文件複製,一次讀一個字符 17 method1(fr, fw); 18 //文本文件複製,一次讀一個字符數組 19 method2(fr, fw); 20 21 fr.close(); 22 fw.close(); 23 } 24 25 public static void method1(FileReader fr, FileWriter fw) throws IOException { 26 int ch; 27 while((ch=fr.read())!=-1) {//讀數據 28 fw.write(ch);//寫數據 29 } 30 fw.flush(); 31 } 32 33 public static void method2(FileReader fr, FileWriter fw) throws IOException { 34 char chs[]=new char[1024]; 35 int len=0; 36 while((len=fr.read(chs))!=-1) {//讀數據 37 fw.write(chs,0,len);//寫數據 38 } 39 fw.flush(); 40 } 41 }
字符緩衝流具有文本特有的表現形式,行操做dom
public class BufferedReader extends Readeride
(1)從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。工具
(2)能夠指定緩衝區的大小,或者可以使用默認的大小。大多數狀況下,默認值就足夠大了。學習
(3)一般,Reader 所做的每一個讀取請求都會致使對底層字符或字節流進行相應的讀取請求。所以,建議用 BufferedReader 包裝全部其 read() 操做可能開銷很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in
= new BufferedReader(new FileReader("foo.in"));
(4)將緩衝指定文件的輸入。若是沒有緩衝,則每次調用 read() 或 readLine() 都會致使從文件中讀取字節,並將其轉換爲字符後返回,而這是極其低效的。
public class BufferedWriter extends Writer
(1)將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。
(2)能夠指定緩衝區的大小,或者接受默認的大小。在大多數狀況下,默認值就足夠大了。
(3)該類提供了 newLine() 方法,它使用平臺本身的行分隔符概念,此概念由系統屬性 line.separator 定義。並不是全部平臺都使用新行符 ('\n') 來終止各行。所以調用此方法來終止每一個輸出行要優於直接寫入新行符。
(4)一般 Writer 將其輸出當即發送到底層字符或字節流。除非要求提示輸出,不然建議用 BufferedWriter 包裝全部其 write() 操做可能開銷很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
(5)緩衝 PrintWriter 對文件的輸出。若是沒有緩衝,則每次調用 print() 方法會致使將字符轉換爲字節,而後當即寫入到文件,而這是極其低效的。
使用BufferedReader和BufferedWriter完成文件複製
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileReader; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 7 public class CopyFile2 { 8 public static void main(String[] args) throws IOException { 9 //建立輸入流對象 10 BufferedReader br=new BufferedReader(new FileReader("C:\\Test\\copyfrom.txt"));//文件不存在會拋出java.io.FileNotFoundException 11 //建立輸出流對象 12 BufferedWriter bw=new BufferedWriter(new FileWriter("C:\\Test\\copyto.txt")); 13 //文本文件複製 14 char [] chs=new char[1024]; 15 int len=0; 16 while((len=br.read(chs))!=-1) { 17 bw.write(chs, 0, len); 18 } 19 //釋放資源 20 br.close(); 21 bw.close(); 22 } 23 }
緩衝區的工做原理:一、使用了底層流對象從具體設備上獲取數據,並將數據存儲到緩衝區的數組內。二、經過緩衝區的read()方法從緩衝區獲取具體的字符數據,這樣就提升了效率。三、若是用read方法讀取字符數據,並存儲到另外一個容器中,直到讀取到了換行符時,將另外一個容器臨時存儲的數據轉成字符串返回,就造成了readLine()功能。
public class FileInputStream extends InputStream
(1)FileInputStream
從文件系統中的某個文件中得到輸入字節。哪些文件可用取決於主機環境。
(2)FileInputStream
用於讀取諸如圖像數據之類的原始字節流。
構造方法摘要 | |
---|---|
FileInputStream(File file) 經過打開一個到實際文件的鏈接來建立一個 FileInputStream ,該文件經過文件系統中的 File 對象 file 指定。 |
|
FileInputStream(FileDescriptor fdObj) 經過使用文件描述符 fdObj 建立一個 FileInputStream ,該文件描述符表示到文件系統中某個實際文件的現有鏈接。 |
|
FileInputStream(String name) 經過打開一個到實際文件的鏈接來建立一個 FileInputStream ,該文件經過文件系統中的路徑名 name 指定。 |
public class FileOutputStream extends OutputStream
(1)文件輸出流是用於將數據寫入 File
或 FileDescriptor
的輸出流。文件是否可用或可否能夠被建立取決於基礎平臺。特別是某些平臺一次只容許一個 FileOutputStream(或其餘文件寫入對象)打開文件進行寫入。在這種狀況下,若是所涉及的文件已經打開,則此類中的構造方法將失敗。(2) FileOutputStream
用於寫入諸如圖像數據之類的原始字節的流。
構造方法摘要 | |
---|---|
FileOutputStream(File file) 建立一個向指定 File 對象表示的文件中寫入數據的文件輸出流。 |
|
FileOutputStream(File file, boolean append) 建立一個向指定 File 對象表示的文件中寫入數據的文件輸出流。 |
|
FileOutputStream(FileDescriptor fdObj) 建立一個向指定文件描述符處寫入數據的輸出文件流,該文件描述符表示一個到文件系統中的某個實際文件的現有鏈接。 |
|
FileOutputStream(String name) 建立一個向具備指定名稱的文件中寫入數據的輸出文件流。 |
|
FileOutputStream(String name, boolean append) 建立一個向具備指定 name 的文件中寫入數據的輸出文件流。 |
例:使用字節流複製圖片
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 5 public class CopImg { 6 public static void main(String[] args) throws IOException { 7 FileInputStream fin=new FileInputStream("C:\\Users\\Administrator\\Desktop\\Img.jpg"); 8 FileOutputStream fout=new FileOutputStream("C:\\Users\\Administrator\\Desktop\\ImgCopy.jpg"); 9 int len=0; 10 byte[] buff=new byte[1024]; 11 while((len=fin.read(buff))!=-1) { 12 fout.write(buff, 0, len); 13 } 14 fin.close(); 15 fout.close(); 16 } 17 }
public class BufferedInputStream extends FilterInputStream
BufferedInputStream
爲另外一個輸入流添加一些功能,即緩衝輸入以及支持 mark
和 reset
方法的能力。在建立 BufferedInputStream
時,會建立一個內部緩衝區數組。在讀取或跳過流中的字節時,可根據須要從包含的輸入流再次填充該內部緩衝區,一次填充多個字節。mark
操做記錄輸入流中的某個點,reset
操做使得在從包含的輸入流中獲取新字節以前,再次讀取自最後一次 mark
操做後讀取的全部字節。
public class BufferedOutputStream extends FilterOutputStream
該類實現緩衝的輸出流。經過設置這種輸出流,應用程序就能夠將各個字節寫入底層輸出流中,而沒必要針對每次字節寫入調用底層系統。
例:使用字節緩衝流實現圖片的複製
1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 7 public class CopyImg { 8 public static void main(String[] args) throws IOException { 9 BufferedInputStream bfin=new BufferedInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\Img.jpg")); 10 BufferedOutputStream bfout=new BufferedOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\ImgCopybuff.jpg")); 11 int len=0; 12 byte[] buff=new byte[1024]; 13 while((len=bfin.read(buff))!=-1) { 14 bfout.write(buff, 0, len); 15 } 16 bfin.close(); 17 bfout.close(); 18 } 19 }
InputStreamReader和OutputStreamWriter是字符和字節的橋樑,也可稱之爲字符轉換流。原理:字節流+編碼。
FileReader和FileWriter做爲子類,僅做爲操做字符文件的便捷類存在。當操做的字符文件,使用的是默認編碼表時能夠不用父類,而直接使用子類完成操做,簡化代碼。
一旦要指定其餘編碼時,不能使用子類,必須使用字符轉換流。
public class InputStreamReader extends Reader
(1)InputStreamReader 是字節流通向字符流的橋樑:它使用指定的 charset
讀取字節並將其解碼爲字符。它使用的字符集能夠由名稱指定或顯式給定,或者能夠接受平臺默認的字符集。
(2)每次調用 InputStreamReader 中的一個 read() 方法都會致使從底層輸入流讀取一個或多個字節。要啓用從字節到字符的有效轉換,能夠提早從底層流讀取更多的字節,使其超過知足當前讀取操做所需的字節。
(3)爲了達到最高效率,能夠考慮在 BufferedReader 內包裝 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));//重要
1 import java.io.BufferedReader; 2 import java.io.FileWriter; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.io.Reader; 7 8 /** 9 * 使用標準輸入流,讀取鍵盤錄入的數據,存儲到項目根目錄下的a.txt中 10 * 將字節輸入流轉換成字符輸入流,InputStreamReader 11 */ 12 public class InputStreamReaderDemo { 13 public static void main(String[] args) throws IOException { 14 //建立輸入流對象 15 BufferedReader r=new BufferedReader(new InputStreamReader(System.in)); 16 //建立輸出流對象 17 FileWriter fw=new FileWriter("a.txt"); 18 //讀寫數據 19 char[] chs=new char[1024]; 20 int len; 21 while((len=r.read(chs))!=-1) { 22 fw.write(chs,0,len); 23 fw.flush(); 24 } 25 //釋放資源 26 r.close(); 27 fw.close(); 28 29 } 30 31 public static void method2() throws IOException { 32 //建立輸入流對象 33 InputStream is=System.in; 34 Reader r=new InputStreamReader(is); 35 //建立輸出流對象 36 FileWriter fw=new FileWriter("a.txt"); 37 38 //讀寫數據 39 char[] chs=new char[1024]; 40 int len; 41 while((len=r.read(chs))!=-1) { 42 fw.write(chs,0,len); 43 fw.flush(); 44 } 45 //釋放資源 46 is.close(); 47 fw.close(); 48 } 49 50 public static void method1() throws IOException { 51 //建立輸入流對象 52 InputStream is=System.in; 53 //建立輸出流對象 54 FileWriter fw=new FileWriter("a.txt"); 55 56 //讀寫數據 57 byte[] bys=new byte[1024]; 58 int len; 59 while((len=is.read(bys))!=-1) { 60 fw.write(new String(bys,0,len)); 61 fw.flush(); 62 } 63 //釋放資源 64 is.close(); 65 fw.close(); 66 } 67 }
public class OutputStreamWriter extends Writer
(1)OutputStreamWriter 是字符流通向字節流的橋樑:可以使用指定的 charset
將要寫入流中的字符編碼成字節。它使用的字符集能夠由名稱指定或顯式給定,不然將接受平臺默認的字符集。
(2)每次調用 write() 方法都會致使在給定字符(或字符集)上調用編碼轉換器。在寫入底層輸出流以前,獲得的這些字節將在緩衝區中累積。能夠指定此緩衝區的大小,不過,默認的緩衝區對多數用途來講已足夠大。注意,傳遞給 write() 方法的字符沒有緩衝。
(3)爲了得到最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以免頻繁調用轉換器。例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));//重要
例如:利用標準輸出流將文本輸出到命令行
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.OutputStream; 7 import java.io.OutputStreamWriter; 8 import java.io.Writer; 9 10 /** 11 * 讀取項目目錄下的文件copy.java,並輸出到命令行 12 * 因爲標準輸出流是字節輸出流,因此只能輸出字節或者字節數組,可是咱們讀取到的數據是字符串,若是想進行輸出, 13 * 還須要轉換成字節數組(method1)。 14 * 要想經過標準輸出流輸出字符串,把標準輸出流轉換成一種字符輸出流便可(method2)。 15 */ 16 public class OutputStreamWriterDemo { 17 public static void main(String[] args) throws IOException { 18 //建立輸入流 19 BufferedReader br=new BufferedReader(new FileReader("copy.java")); 20 //建立輸出流 21 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); 22 String line;//用於接收讀到的數據 23 while((line=br.readLine())!=null) { 24 bw.write(line); 25 bw.write("\r\n"); 26 } 27 br.close(); 28 bw.close(); 29 } 30 31 public static void method2() throws FileNotFoundException, IOException { 32 //建立輸入流 33 BufferedReader br=new BufferedReader(new FileReader("copy.java")); 34 //建立輸出流 35 //OutputStream os=System.out; 36 Writer w=new OutputStreamWriter(System.out);//多態,父類引用指向子類對象 37 String line;//用於接收讀到的數據 38 while((line=br.readLine())!=null) { 39 w.write(line); 40 w.write("\r\n"); 41 } 42 br.close(); 43 w.close(); 44 } 45 46 public static void method1() throws FileNotFoundException, IOException { 47 //建立輸入流 48 BufferedReader br=new BufferedReader(new FileReader("copy.java")); 49 //建立輸出流 50 OutputStream os=System.out; 51 String line;//用於接收讀到的數據 52 while((line=br.readLine())!=null) { 53 os.write(line.getBytes()); 54 os.write("\r\n".getBytes()); 55 } 56 br.close(); 57 os.close(); 58 } 59 }
1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.OutputStreamWriter; 7 import java.io.UnsupportedEncodingException; 8 9 public class TransStreamDemo { 10 public static void main(String[] args) throws IOException { 11 writeCN(); 12 readCN(); 13 } 14 15 public static void readCN() throws UnsupportedEncodingException, FileNotFoundException, IOException { 16 //InputStreamReader將字節數組使用指定的編碼表解碼成文字 17 InputStreamReader isr=new InputStreamReader(new FileInputStream("temp.txt"),"utf-8"); 18 char[] buff=new char[1024]; 19 int len=isr.read(buff); 20 System.out.println(new String(buff,0,len)); 21 isr.close(); 22 } 23 24 public static void writeCN() throws UnsupportedEncodingException, FileNotFoundException, IOException { 25 //OutputStreamWriter將字符串按照指定的編碼表轉成字節,再使用字符流將這些字節寫出去 26 OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("temp.txt"),"utf-8");//自己是字符流,傳入字節流 27 osw.write("你好"); 28 osw.close(); 29 } 30 }
public class PrintWriter extends Writer
(1)向文本輸出流打印對象的格式化表示形式。此類實如今 PrintStream
中的全部 print 方法。不能輸出字節,可是能夠輸出其餘任意類型。
(2)與 PrintStream
類不一樣,若是啓用了自動刷新,則只有在調用 println、printf 或 format 的其中一個方法時纔可能完成此操做,而不是每當正好輸出換行符時才完成。這些方法使用平臺自有的行分隔符概念,而不是換行符。
(3)此類中的方法不會拋出 I/O 異常,儘管其某些構造方法可能拋出異常。客戶端可能會查詢調用 checkError()
是否出現錯誤。
1 import java.io.FileWriter; 2 import java.io.IOException; 3 import java.io.PrintWriter; 4 /** 5 * 注意:建立FileWriter對象時boolean參數表示是否追加; 6 * 而建立打印流對象時boolean參數表示是否自動刷新 7 */ 8 public class PrintWriterDemo { 9 public static void main(String[] args) throws IOException { 10 //PrintWriter pw=new PrintWriter("print.txt"); 11 PrintWriter pw=new PrintWriter(new FileWriter("print.txt"),true); 12 pw.write("測試打印流"); 13 pw.println("此句以後換行"); 14 pw.println("特有功能:自動換行和自動刷新"); 15 pw.println("利用構造器設置自動刷新"); 16 pw.close(); 17 } 18 }
使用字符打印流複製文本文件:
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.FileWriter; 4 import java.io.IOException; 5 import java.io.PrintWriter; 6 /** 7 * 使用打印流複製文本文件 8 */ 9 public class PrintWriterDemo { 10 public static void main(String[] args) throws IOException { 11 BufferedReader br=new BufferedReader(new FileReader("copy.java")); 12 PrintWriter pw=new PrintWriter("printcopy.java"); 13 String line; 14 while((line=br.readLine())!=null) { 15 pw.println(line); 16 } 17 br.close(); 18 pw.close(); 19 } 20 }
public class PrintStream extends FilterOutputStreamimplements Appendable, Closeable
爲其餘輸出流添加了功能(增長了不少打印方法),使它們可以方便地打印各類數據值表示形式(例如:但願寫一個整數,到目的地整數的表現形式不變。字節流的write方法只將一個整數的最低字節寫入到目的地,好比寫fos.write(97),到目的地(記事本打開文件)會變成字符'a',須要手動轉換:fos.write(Integer.toString(97).getBytes());而採用PrintStream:ps.print(97),則能夠保證數據的表現形式)。
(1)PrintStream
1 //PrintStream的print方法 2 public void print(int i) { 3 write(String.valueOf(i)); 4 }
(2)與其餘輸出流不一樣, 永遠不會拋出 ;而是,異常狀況僅設置可經過 方法測試的內部標誌。
另外,爲了自動刷新,能夠建立一個 ;這意味着可在寫入 byte 數組以後自動調用 方法,可調用其中一個 方法,或寫入一個換行符或字節 ()。
打印的全部字符都使用平臺的默認字符編碼轉換爲字節。在須要寫入字符而不是寫入字節的狀況下,應該使用 類。
使用字節打印流複製文本文件:
PrintStreamIOExceptioncheckErrorPrintStreamflushprintln'\n'(3)PrintStreamPrintWriter
PrintWriter
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.PrintStream; 5 6 public class PrintStreamDemo { 7 public static void main(String[] args) throws IOException { 8 BufferedReader br=new BufferedReader(new FileReader("copy.java")); 9 PrintStream ps=new PrintStream("printcopy2.java"); 10 String line; 11 while((line=br.readLine())!=null) { 12 ps.println(line); 13 } 14 br.close(); 15 ps.close(); 16 } 17 }
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants
(1)ObjectOutputStream 將 Java 對象的基本數據類型和圖形寫入 OutputStream。只能使用 ObjectInputStream 讀取(重構)對象。
(2)只能將支持 java.io.Serializable 接口的對象寫入流中。
(3)writeObject 方法用於將對象寫入流中。全部對象(包括 String 和數組)均可以經過 writeObject 寫入。可將多個對象或基元寫入流中。必須使用與寫入對象時相同的類型和順序從相應 ObjectInputstream 中讀回對象。
構造方法:ObjectOutputStream(OutputStream out)
建立寫入指定 OutputStream 的 ObjectOutputStream。
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants
(1)ObjectInputStream 對之前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化。
(2)只有支持 java.io.Serializable 或 java.io.Externalizable 接口的對象才能從流讀取。
(3)readObject
方法用於從流讀取對象。應該使用 Java 的安全強制轉換來獲取所需的類型。在 Java 中,字符串和數組都是對象,因此在序列化期間將其視爲對象。讀取時,須要將其強制轉換爲指望的類型。
例:對象讀寫:
1 import java.io.Serializable; 2 //學生類 3 public class Student implements Serializable{ 4 private static final long serialVersionUID = -8942780382144699003L; 5 String name; 6 int age; 7 public Student(String name,int age){ 8 this.name=name; 9 this.age=age; 10 } 11 @Override 12 public String toString() { 13 return "Student [name=" + name + ", age=" + age + "]"; 14 } 15 }
1 import java.io.EOFException; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.ObjectInputStream; 7 import java.io.ObjectOutputStream; 8 9 /** 10 * 使用對象輸出流寫對象和對象輸入流讀對象 11 *注意:若是Student沒有序列化,會拋出java.io.NotSerializableException 12 *Serializable:序列號,是一個標識接口,只起標識做用,沒有方法 13 *當一個類的對象須要IO流進行讀寫的時候,這個類必須實現接口 14 */ 15 public class ObjectOperate { 16 public static void main(String[] args) throws IOException, ClassNotFoundException { 17 writeObject(); 18 //建立對象輸入流的對象 19 ObjectInputStream ois=new ObjectInputStream(new FileInputStream("a.txt")); 20 //讀取對象 21 try { 22 while(true){ 23 Object obj=ois.readObject(); 24 System.out.println(obj); 25 } 26 }catch(EOFException e){ 27 System.out.println("讀到了文件末尾"); 28 } 29 30 //釋放資源 31 ois.close(); 32 33 } 34 35 public static void writeObject() throws FileNotFoundException, IOException { 36 //建立對象輸出流的對象 37 FileOutputStream fos=new FileOutputStream("a.txt"); 38 ObjectOutputStream oos=new ObjectOutputStream(fos); 39 //建立學生對象 40 Student s1=new Student("張三",20); 41 Student s2=new Student("李四",30); 42 Student s3=new Student("王五",10); 43 //寫出學生對象 44 oos.writeObject(s1); 45 oos.writeObject(s2); 46 oos.writeObject(s3); 47 //釋放資源 48 } 49 }
1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.io.ObjectInputStream; 6 import java.io.ObjectOutputStream; 7 import java.util.ArrayList; 8 /** 9 * 使用對象輸出流寫對象和對象輸入流讀對象 10 *解決讀取對象出現異常的問題,使用集合類 11 */ 12 public class ObjectOperate2 { 13 public static void main(String[] args) throws IOException, ClassNotFoundException { 14 listMethod(); 15 //建立對象輸入流對象 16 ObjectInputStream ois=new ObjectInputStream(new FileInputStream("b.txt")); 17 //讀取數據 18 Object obj=ois.readObject(); 19 //System.out.println(obj); 20 //向下轉型 21 ArrayList<Student> list=(ArrayList<Student>) obj; 22 for(Student s:list) { 23 System.out.println(s); 24 } 25 //釋放資源 26 ois.close(); 27 } 28 29 public static void listMethod() throws IOException, FileNotFoundException { 30 //建立對象輸出流的對象 31 ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("b.txt")); 32 //建立集合類 33 ArrayList<Student> list=new ArrayList<Student>(); 34 //添加學生對象 35 list.add(new Student("zhangsan",20)); 36 list.add(new Student("lisi",30)); 37 //寫出集合對象 38 oos.writeObject(list); 39 //釋放資源 40 oos.close(); 41 } 42 43 }
序列化接口Serializable的做用:沒有方法,不須要覆寫,是一個標記接口爲了啓動一個序列化功能。惟一的做用就是給每個須要序列化的類都分配一個序列版本號,這個版本號和類相關聯。在序列化時,會將這個序列號也一同保存在文件中,在反序列化時會讀取這個序列號和本類的序列號進行匹配,若是不匹配會拋出java.io.InvalidClassException.
注意:靜態數據不會被序列化,由於靜態數據在方法區,不在對象裏。
或者使用transient關鍵字修飾,也不會序列化。
表示其餘輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直到到達文件末尾,接着從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的文件末尾爲止。
案例:媒體文件切割與合併
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.util.Properties; 6 7 public class CutFile { 8 /** 9 * 將一個媒體文件切割成碎片 10 * 思路:一、讀取源文件,將源文件的數據分別複製到多個文件 11 * 二、切割方式有兩種:按照碎片個數切,或者按照指定大小切 12 * 三、一個輸入流對應多個輸出流 13 * 四、每一個碎片都須要編號,順序不能錯 14 * @throws IOException 15 */ 16 public static void main(String[] args) throws IOException { 17 File srcFile=new File("C:\\Users\\Administrator\\Desktop\\Test\\img.jpg"); 18 File partsDir=new File("C:\\Users\\Administrator\\Desktop\\cutFiles"); 19 splitFile(srcFile,partsDir); 20 21 } 22 //切割文件 23 private static void splitFile(File srcFile, File partsDir) throws IOException { 24 if(!(srcFile.exists()&&srcFile.isFile())) { 25 throw new RuntimeException("源文件不是正確文件或者不存在"); 26 } 27 if(!partsDir.exists()) { 28 partsDir.mkdirs(); 29 } 30 FileInputStream fis=new FileInputStream(srcFile); 31 FileOutputStream fos=null; 32 33 byte[] buf=new byte[1024*60]; 34 35 int len=0; 36 int count=1; 37 while((len=fis.read(buf))!=-1) { 38 //存儲碎片文件 39 fos=new FileOutputStream(new File(partsDir,(count++)+".part")); 40 fos.write(buf, 0, len); 41 fos.close(); 42 } 43 /*將源文件和切割的信息也保存起來,隨着碎片文件一塊兒發送 44 * 信息:源文件的名稱 45 * 碎片的個數 46 *將這些信息單獨封裝到一個文件中 47 *還要一個輸出流完成此操做 */ 48 49 String fileName=srcFile.getName(); 50 int partCount=count; 51 fos=new FileOutputStream(new File(partsDir,count+".properties")); 52 // fos.write(("fileName="+fileName+System.lineSeparator()).getBytes()); 53 // fos.write(("fileCount="+Integer.toString(partCount)).getBytes()); 54 Properties prop=new Properties(); 55 prop.setProperty("fileName", srcFile.getName()); 56 prop.setProperty("partCount", Integer.toString(partCount)); 57 //將屬性集中的信息持久化 58 prop.store(fos, "part file info"); 59 fis.close(); 60 fos.close(); 61 62 } 63 }
1 import java.io.File; 2 import java.io.FileFilter; 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.SequenceInputStream; 8 import java.util.ArrayList; 9 import java.util.Collections; 10 import java.util.Enumeration; 11 import java.util.List; 12 import java.util.Properties; 13 14 public class mergeFile { 15 public static void main(String[] args) throws IOException { 16 File pathDir=new File("C:\\Users\\Administrator\\Desktop\\cutFiles"); 17 //獲取配置文件 18 File configFile=getconfigFile(pathDir); 19 //獲取配置文件信息的屬性集 20 Properties prop=getProperties(configFile); 21 System.out.println(prop); 22 //獲取屬性集信息,將屬性集信息傳遞到合併方法中 23 merge(pathDir,prop); 24 } 25 26 private static Properties getProperties(File configFile) throws IOException { 27 FileInputStream fis=null; 28 Properties prop=null; 29 try { 30 //讀取流和配置文件相關聯 31 fis=new FileInputStream(configFile); 32 prop=new Properties(); 33 //流中的數據加載到集合中 34 prop.load(fis); 35 }finally { 36 if(fis!=null) { 37 fis.close(); 38 } 39 } 40 return prop; 41 } 42 43 public static File getconfigFile(File pathDir) { 44 //判斷是否存在properties文件 45 if(!(pathDir.exists()&&pathDir.isDirectory())) { 46 throw new RuntimeException(pathDir.toString()+"不是有效目錄"); 47 } 48 File[] files=pathDir.listFiles(new FileFilter() { 49 @Override 50 public boolean accept(File pathname) { 51 return pathname.getName().endsWith(".properties"); 52 } 53 54 }); 55 if(files.length!=1) { 56 throw new RuntimeException(pathDir.toString()+"properties擴展名的文件不存在或者不惟一"); 57 } 58 File configFile=files[0]; 59 return configFile; 60 } 61 62 public static void merge(File pathDir, Properties prop) throws FileNotFoundException, IOException { 63 String fileName=prop.getProperty("fileName"); 64 int partCount=Integer.valueOf(prop.getProperty("partCount")); 65 List<FileInputStream> list=new ArrayList<FileInputStream>(); 66 for(int i=1;i<partCount;i++) { 67 list.add(new FileInputStream(pathDir.toString()+"\\"+i+".part")); 68 } 69 //List自身沒法獲取Enumeration工具類,到Collection中找 70 Enumeration<FileInputStream> en=Collections.enumeration(list); 71 SequenceInputStream sis=new SequenceInputStream(en); 72 FileOutputStream fos=new FileOutputStream(pathDir.toString()+"\\"+fileName); 73 byte[] buf=new byte[1024]; 74 int len=0; 75 while((len=sis.read(buf))!=-1) { 76 fos.write(buf,0,len); 77 } 78 fos.close(); 79 sis.close(); 80 } 81 82 }
ByteArrayInputStream ByteArrayOutputStream
CharArrayReader CharArrayWriter
StringReader StringWriter
關閉這些流都是無效的,由於這些都未調用系統資源,不須要拋IO異常。
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 4 /** 5 * 源和目的都是內存的讀寫過程 6 *用流的思想操做數組中的數據 7 */ 8 public class ByteArrayStreamDemo { 9 public static void main(String[] args) { 10 //源:內存 11 ByteArrayInputStream bis=new ByteArrayInputStream("andhhshad".getBytes()); 12 //目的:內存 13 ByteArrayOutputStream bos=new ByteArrayOutputStream();//內部有個可自動增加的數組 14 //由於都是源和目的都是內存,沒有調用底層資源,因此不要關閉,即便調用了close也沒有任何效果,關閉後仍然可以使用,不會拋出異常。 15 int ch=0; 16 while((ch=bis.read())!=-1) { 17 bos.write(ch); 18 } 19 20 System.out.println(bos.toString()); 21 } 22 }
1 import java.io.FileNotFoundException; 2 import java.io.IOException; 3 import java.io.RandomAccessFile; 4 5 /** 6 * 注意:隨機讀寫。數據須要規律。用RandomAccessFile類須要明確要操做的數據的位置。 7 * 8 */ 9 public class RandomAccessFileDemo { 10 public static void main(String[] args) throws IOException { 11 //writeFile(); 12 RandomAccessFile raf=new RandomAccessFile("tempFile\\test.txt","r"); 13 raf.seek(8*1);//讀第二我的 14 byte[] buf=new byte[4]; 15 raf.read(buf); 16 String name=new String(buf); 17 System.out.println("name="+name); 18 19 int age=raf.readInt(); 20 System.out.println("age="+age); 21 raf.close(); 22 } 23 24 public static void writeFile() throws FileNotFoundException, IOException { 25 //明確要操做的位置,能夠多個線程操做同一份文件而不衝突。多線程下載的基本原理。 26 RandomAccessFile raf=new RandomAccessFile("tempFile\\test.txt","rw"); 27 28 raf.write("張三".getBytes()); 29 raf.writeInt(97);//保證字節原樣性 30 31 raf.write("李四".getBytes()); 32 raf.writeInt(99);//保證字節原樣性 33 34 System.out.println(raf.getFilePointer());//獲取隨機指針 35 raf.seek(8*2);//設置指針 36 raf.write("王五".getBytes()); 37 raf.writeInt(100);//保證字節原樣性 38 raf.close(); 39 } 40 }
File: 文件和目錄路徑名的抽象表示形式,File類的實例是不可改變的
(1)File類經常使用功能
File: 文件和目錄路徑名的抽象表示形式,File類的實例是不可改變的 * File類的構造方法: * File(String pathname) 將指定的路徑名轉換成一個File對象 * File(String parent,String child) 根據指定的父路徑和文件路徑建立對象 * File(File parent,String child) * File類經常使用功能: * 建立:boolean createNewFile():當指定文件(或文件夾)不存在時建立文件並返回true,不然返回false,路徑不存在則拋出異常 * boolean mkdir() :當指定文件(或文件夾)不存在時建立文件夾並返回true,不然返回false * boolean mkdirs() :建立指定文件夾,所在文件夾目錄不存在時,則順道一塊建立
* 刪除:boolean delete():刪除文件 注意:要刪除一個目錄,須要先刪除這個目錄下的全部子文件和子目錄 * 獲取:File getAbsoluteFile() * File getParentFile() * String getAbsolutePath() * String getParent() * String getPath() * long lastModified()
* 判斷: boolean exists(); * boolean isAbsolute() * boolean isDirectory() * boolean isFile() * boolean isHidden() * 修改:boolean renameTo(File dest): 將當前File對象所指向的路徑修改成指定File所指的路徑 (修改文件名稱)
案例:打印指定文件(夾)及其全部子目錄
1 import java.io.File; 2 /**
3 *打印目錄 4 */
5 public class FileDemo1 { 6 public static void main(String[] args){ 7 File f=new File("E:\\BaiduNetdiskDownload"); 8 printTree( f,0); 9 } 10
11 public static void printTree(File f,int level) { 12 for(int j=0;j<level;j++) { 13 System.out.print("\t"); 14 } 15 System.out.println(f.getAbsolutePath()); 16 if(f.isDirectory()) { 17 level++; 18 File strs[]=f.listFiles(); 19 for(int i=0;i<strs.length;i++) { 20 File f0=strs[i]; 21 printTree(f0,level+1); 22 } 23 } 24 } 25 }
(2)File類重要方法之過濾器
String[] list()
String[] list(FilenameFilter)
File[] listFiles()
File[] listFiles(FilenameFilter)
File[] listFiles(FileFilter filter)
File類的list方法能夠獲取目錄下的各個文件,傳入過濾器還能按照特定需求取出須要的文件。下面來看一下過濾器怎麼用的。首先看
String[] list(FilenameFilter)
查看FilenameFilter源碼,發現實際上是一個接口:
public interface FilenameFilter { /** * Tests if a specified file should be included in a file list. * * @param dir the directory in which the file was found. * @param name the name of the file. * @return <code>true</code> if and only if the name should be * included in the file list; <code>false</code> otherwise. */
boolean accept(File dir, String name); }
那麼咱們要想使用過濾器,應該先實現接口,假設咱們要找某個文件夾下的txt文件:
1 import java.io.File; 2 import java.io.FilenameFilter; 3 4 public class FileDemo { 5 public static void main(String[] args) { 6 File file = new File("C:\\Test"); 7 if(file.isDirectory()) { 8 String[] list=file.list(new FilenameFilterbytxt());//傳入過濾器 9 for(String l:list) { 10 System.out.println(l); 11 } 12 } 13 } 14 } 15 16 class FilenameFilterbytxt implements FilenameFilter{ 17 @Override 18 public boolean accept(File dir, String name) { 19 // TODO Auto-generated method stub 20 return name.endsWith(".txt");//當文件名以.txt結尾時返回true. 21 } 22 23 }
可是咱們看到第8行代碼只是傳入了過濾器,那麼accept方法是如何被調用的呢?查看
String[] list(FilenameFilter) 的源碼:
1 /*list(FilenameFilter)源碼解析*/
2 public String[] list(FilenameFilter filter) { 3 String names[] = list();//調用list()方法獲取全部名稱
4 if ((names == null) || (filter == null)) { 5 return names; 6 } 7 List<String> v = new ArrayList<>();//用於保存過濾後的文件名
8 for (int i = 0 ; i < names.length ; i++) {//遍歷 9 //調用filter的accept方法,傳入當前目錄this和遍歷到的名稱names[i]
10 if (filter.accept(this, names[i])) { 11 v.add(names[i]);//知足過濾器條件的添加到集合中
12 } 13 } 14 return v.toArray(new String[v.size()]);//將集合轉成數組返回,限定增刪操做
15 }
也就是說,咱們實現的accept方法是在構造器中被調用的。
相似地,FileFilter 也是一個接口,採用匿名內部類的方式實現接口,使用File[] listFiles(FileFilter filter)獲取目錄下全部文件夾:
1 import java.io.File; 2 import java.io.FileFilter; 3 4 public class FileDemo { 5 public static void main(String[] args) { 6 File file = new File("C:\\Test"); 7 if(file.isDirectory()) { 8 File[] list=file.listFiles(new FileFilter() { 9 @Override 10 public boolean accept(File pathname) { 11 // TODO Auto-generated method stub 12 return pathname.isDirectory(); 13 } 14 15 }); 16 17 for(File f:list) { 18 System.out.println(f); 19 } 20 } 21 } 22 }
File[] listFiles(FileFilter filter) 方法的源碼以下:
1 /*File[] listFiles(FileFilter filter)源碼解析*/ 2 public File[] listFiles(FileFilter filter) { 3 String ss[] = list();//調用list()獲取全部的名稱數組 4 if (ss == null) return null;//健壯性判斷,數組爲null則返回 5 ArrayList<File> files = new ArrayList<>();//建立File類型集合 6 for (String s : ss) {//遍歷 7 File f = new File(s, this);//private File(String child, File parent)私有構造調用 8 if ((filter == null) || filter.accept(f))//條件判斷 9 files.add(f);//添加到集合 10 } 11 return files.toArray(new File[files.size()]);//集合轉成數組返回 12 }
十二、IO流使用規律總結:
(1)明確要操做的數據是數據源仍是數據目的(要讀仍是要寫)
源:InputStream Reader
目的:OutputStream Writer
(2)明確要操做的設備上的數據是字節仍是文本
源:
字節:InputStream
文本:Reader
目的:
字節:OutputStream
文本:Writer
(3)明確數據所在的具體設備
源設備:
硬盤:文件 File開頭
內存:數組,字符串
鍵盤:System.in
網絡:Socket
目的設備:
硬盤:文件 File開頭
內存:數組,字符串
屏幕:System.out
網絡:Socket
(4)明確是否須要額外功能?
須要轉換——轉換流 InputStreamReader OutputStreamWriter
須要高效——緩衝流Bufferedxxx
多個源——序列流 SequenceInputStream
對象序列化——ObjectInputStream,ObjectOutputStream
保證數據的輸出形式——打印流PrintStream Printwriter
操做基本數據,保證字節原樣性——DataOutputStream,DataInputStream