JDK提供的流繼承了四大類:InputStream(字節輸入流)、OutputStream(字節輸出流)、Reader(字符輸入流)、Writer(字符輸出流)。
字符流和字節流的主要區別: 1.字節流讀取的時候,讀到一個字節就返回一個字節; 字符流使用了字節流讀到一個或多個字節(中文對應的字節數是兩個,在UTF-8碼表中是3個字節)時。先去查指定的編碼表,將查到的字符返回。 2.字節流可以處理所有類型數據,如:圖片,MP3,AVI視頻文件,而字符流只能處理字符數據。 只要是處理純文本數據,就要優先考慮使用字符流,除此之外都用字節流。 詳解如下: 一、字節流講解 1.用流對文件進行處理package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class TestIO { public static void main(String[] args) { File file = new File("E:/java.txt"); if (!file.exists()) { //先判斷該目錄文件是否存在 try { //file.mkdirs(); 創建該目錄下指定的文件夾 file.createNewFile(); // 當文件不存在時,創建此文件夾 } catch (Exception e) { e.printStackTrace(); } } //file.delete(); //刪除指定的文件 System.out.println("文件名:"+file.getName()); } }
2. InputStream 和 OutputStream 是兩個 abstact 類,對於字節為導向的 stream 都擴展這兩個基類;
inputStream中的關鍵方法:
read():方法是讀取一個byte字節,但是返回的是int。 read(byte[]):一次性讀取內容到緩沖字節數組 read(byte[],int,int):從數據流中的哪個位置offset開始讀長度為len的內容到緩沖字節數組OutputStream中的關鍵方法
write(int):寫入一個字節到stream中 write(byte[])寫入一個byte數組到stream中 write(byte[],int,int):把byte數組中從開始處寫入長度為len的數據 flush():這個方法是用來刷新stream中的數據,讓緩沖區中的數據強制的輸出
3.FileInputStream和FileOutputStream
FileInputStream
: 從文件系統中的某個文件中獲得輸入字節.
FileOutputStream
: 文件輸出流是用於將數據寫入 File
或 FileDescriptor
的輸出流.
下面是一個例子:
package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; ReadByFIS(path1, path2); } /** * 使用FileInputStream 將一個文件的內容寫入到另一個文件中,並在控制台輸出 * * @param path1 * @param path2 * @throws Exception */ public static void ReadByFIS(String path1, String path2) throws Exception { InputStream in = new FileInputStream(path1); //創建文件輸入流 OutputStream out = new FileOutputStream(path2); //創建文件輸出流 byte[] buffer = new byte[1024]; //定義字節數組 int len = 0; while ((len = in.read(buffer)) > 0) { //將最多buffer.lenth個字節的數據讀入byte數組中 String s = new String(buffer, 0, len); //將讀入的字節轉換成String類型 System.out.println(s); //輸出讀取到的信息 out.write(buffer, 0, len); //將讀取到的信息寫入到文件中 } out.close(); //關閉輸入輸出流 in.close(); } }輸出結果如下: 如果想讓某個字符串寫入到文件中,如下所示:
package com.chen.Two; import java.io.*; public class Two { // 編寫一個Java程序將111,112,113,114,115 這5個數以寫入到Dest.txt文件中 public static void main(String[] args) throws Exception { String str = "111,112,113,114,115"; //定義字符串 FileOutputStream fo = new FileOutputStream("E:/WorkSpace/Mouth/bin/Dest.txt"); //創建文件輸出流 int len = 0 ; byte[] buffer = str.getBytes(); //將字符串轉換成byte字節 fo.write(buffer); //將字節數組中的數據寫出 fo.close();
}
}
4.BufferedInputStream和Buffered
OutputStream
BufferedInputStream
為另一個輸入流添加一些功能,即緩沖輸入以及支持mark
和reset
方法的能力。 在創建BufferedInputStream
時,會創建一個內部緩沖區數組。 在讀取或跳過流中的字節時,可根據需要從包含的輸入流再次填充該內部緩沖區,一次填充多個字節。mark
操作記錄輸入流中的某個點,reset
操作使得在從包含的輸入流中獲取新字節之前,再次讀取自最後一次mark
操作後讀取的所有字節。
Buffered
OutputStream
該類實現緩沖的輸出流。
通過設置這種輸出流,應用程序就可以將各個字節寫入底層輸出流中,而不必針對每次字節寫入調用底層系統。
下面講一個例子:
package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; ReadByBIS(path1, path2); } /** * 使用BufferInputStream將一個文件的內容寫入到另一個文件中,並在控制台輸出 * * @param path1 * @param path2 * @throws Exception */ public static void ReadByBIS(String path1, String path2) throws Exception { InputStream in = new BufferedInputStream(new FileInputStream(path1)); //創建文件輸入流 OutputStream out = new BufferedOutputStream(new FileOutputStream(path2)); //創建文件輸出流 byte[] buffer = new byte[1024]; //定義字節數組 int len = 0; while ((len = in.read(buffer)) > 0) { //將最多buffer.lenth個字節的數據讀入byte數組中 out.write(buffer, 0, len); //將讀取到的信息寫入到文件中 out.flush(); // 刷新此緩沖的輸出流 String s = new String(buffer, 0, len); //將讀入的字節轉換成String類型 System.out.println(s); //輸出讀取到的信息 } in.close(); //關閉輸入輸出流 out.close(); } }
輸出結果:
如果大家學過設計模式中的裝飾者模式,會很容易發現Bufferedin
putStream
Buffered
OutputStream其實是對
FileInputStream和FileOutputStream進行了包裝。
為它創建一個內部緩沖區數組,應用程序就可以將各個字節讀/寫入底層輸出流中,而不必針對每次字節讀/寫入調用底層系統。
5.讀寫對象:
ObjectInputStream 和ObjectOutputStream
該流允許讀取或寫入用戶自定義的類,但是要實現這種功能,被讀取和寫入的類必須實現Serializable接口, 其實該接口並沒有什麼方法,可能相當 於一個標記而已,但是確實不合缺少的。例子如下:
package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; ReadbyOnjiect(path2); } public static void ReadbyOnjiect(String path2){ ObjectInputStream oibs = null; ObjectOutputStream oobs = null; try { oobs = new ObjectOutputStream(new FileOutputStream(path2)); oobs.writeObject(new Student("張三", 18)); oobs.writeObject(new Student("李四", 18)); oibs = new ObjectInputStream( new FileInputStream(path2)); for(int i=0;i<2;i++){ System.out.println(oibs.readObject()); } } catch (Exception e) { // TODO: handle exception }6
oibs.close();
oobs.close();
} } //自定義的類實現了Serializable接口,可序列化 class Student implements Serializable{ private String name; private int age; public Student(String name,int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student[name="+name+",age="+age+"]"; } }
.讀寫對象:
DataInputStream和DataOutputStream
DataInputStream、DataOutputStream來寫入或讀出數據。DataInputStream的好處在於在從文件讀出數據時,不用費心地自行判斷讀入字符串時或讀入int類型時何時將停止,使用對應的readUTF()和readInt()方法就可以正確地讀入完整的類型數據。
下面是一個例 子:
package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; DataReader(path2); } /** * 用DataOutputStream和DataInputStream將類寫入到文件中,然後讀出 * @param path1 */ public static void DataReader(String path1){ Student[] student = { new Student("zs", 18), new Student("ls", 20)}; try { DataOutputStream oups = new DataOutputStream(new FileOutputStream(path1)); DataInputStream dips = new DataInputStream(new FileInputStream(path1)); for (Student s : student) { //寫入數據 oups.writeUTF(s.getName()); oups.writeInt(s.getAge()); } oups.flush(); oups.close(); for(int i = 0 ; i<student.length;i++){ String name = dips.readUTF(); int age = dips.readInt(); student[i] = new Student(name, age); } for (Student student2 : student) { System.out.println(student2.getName()+" "+student2.getAge()); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class Student implements Serializable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student[name=" + name + ",age=" + age + "]"; } }
二、字符流講解
以字符為導向的 ------Writer和Reader(抽象類) 1.FileReader和FileWriter FileReader:用來讀取字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩沖區大小都是適當的。 FileWriter:用來寫入字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩沖區大小都是可接受的. 下面見一個例子:package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; ReadByFR(path1, path2); } /** * 使用FileReader將一個文件的內容寫入到另一個文件中,並在控制台輸出 * * @param path1 * @param path2 * @throws Exception */ public static void ReadByFR(String path1, String path2) throws Exception { FileReader fr = new FileReader(path1); FileWriter fw = new FileWriter(path2); // 1.將一個文件的內容讀出,寫入 char[] buffer = new char[1024]; int len; while ((len = fr.read(buffer)) > -1) { //將數據讀到char數組中 fw.write(buffer, 0, len);2.BufferedReader和BufferedWriter
fw.flush(); String s = new String(buffer, 0, len); System.out.println(s); } fw.close(); fr.close(); }
下面是個例子:BufferedReader從字符輸入流中讀取文本,緩沖各個字符,從而實現字符、數組和行的高效讀取。
可以指定緩沖區的大小,或者可使用默認的大小。大多數情況下,默認值就足夠大了。
BufferedWriter將文本寫入字符輸出流,緩沖各個字符,從而提供單個字符、數組和字符串的高效寫入。
可以指定緩沖區的大小,或者接受默認的大小。在大多數情況下,默認值就足夠大了。
該類提供了 newLine() 方法,它使用平台自己的行分隔符概念,並非所有平台都使用新行符 ('\n') 來終止各行。因此調用此方法來終止每個輸出行要優於直接寫入新行符。
package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; ReadByBR(path1, path2); } /** * 使用BufferdeReader將一個文件的內容寫入到另一個文件中,並在控制台輸出 * * @param path1 * @param path2 * @throws Exception */ public static void ReadByBR(String path1, String path2) throws Exception { BufferedReader fr = new BufferedReader(new FileReader(path1)); BufferedWriter fw = new BufferedWriter(new FileWriter(path2)); //PrintStream ps = new PrintStream(path2); String len; while ((len = fr.readLine()) != null) { fw.write(len); fw.flush(); //ps.println(len); //ps.flush(); System.out.println(len); } fw.close(); fr.close(); } }
3.InputStreamReader和OutputStreamWriter
InputStreamReader 是字節流通向字符流的橋梁:每次調用 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個字節。
要啟用從字節到字符的有效轉換,可以提前從底層流讀取更多的字節,使其超過滿足當前讀取操作所需的字節。
OutputStreamWriter 是字符流通向字節流的橋梁:
每次調用 write() 方法都會導致在給定字符(或字符集)上調用編碼轉換器。在寫入底層輸出流之前,得到的這些字節將在緩沖區中累積。
可以指定此緩沖區的大小注意,傳遞給 write() 方法的字符沒有緩沖。
package com.chen.test; import java.io.*; /** * * @author 陳家小帥 * */ public class Test4 { public static void main(String[] args) throws Exception { String path1 = "E:/WorkSpace/Mouth/bin/Dest.txt"; String path2 = "E:/WorkSpace/Mouth/bin/D.txt"; ReadByIS(path1, path2); } /** * 使用inputStreamReader將一個文件的內容寫入到另一個文件中,並在控制台輸出 * * @param path1 * @param path2 * @throws Exception */ public static void ReadByIS(String path1, String path2) throws Exception { InputStreamReader isr = new InputStreamReader( new FileInputStream(path1)); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( path2)); char[] cha = new char[1024]; int len; while ((len = isr.read(cha)) > -1) { System.out.println(new String(cha, 0, len)); osw.write(cha, 0, len); osw.flush(); } osw.close(); isr.close(); } }
DataInputStream