三万字的java I/O流基础总结看完肯定能把女朋友教会
目錄:
1.File類詳解
2.I/O流概述
3.字節輸出流(OutputStream)
4.字節輸入流(InputStream)
5. 字符流概述
6.字符輸入流(Reader)
7.字符輸出流(Writer)
8.Properties類詳解
9.緩沖流概述
10.字節緩沖流(BufferedInputStream,BufferedOutputStream)
11.字符緩沖流(BufferedReader,BufferedWriter)
12.緩沖流高效率測試
13.轉換流概述
14. InputStreamReader類和 OutputStreamWriter類
15. 序列化
16.打印流
1.File類詳解
(1)首先File的位置:java.io.File
(2)File的作用
1.File類是專門對文件進行操作的類,只能對文件本身進行操作,不能對文件內容進行操作
2.File類是文件和目錄路徑名的抽象表示,主要用于文件和目錄的創建、查找和刪除等操作
(3)File類的構造方法
說著當然難受,上代碼:
package untl1; import java.io.File; public class MyFile {public static void main(String[] args) {String str1="d:\\1\\a.txt";File file1=new File(str1);//運行結果創建一個為d:\\1\\a.txt的File對象String str2="d:";String str3="1\\a.txt";File file2=new File(str2,str3);//運行結果創建一個為d:\\1\\a.txt的File對象String str4="d:";String str5="1\\a.txt";File file3=new File(str4);File file4=new File(file3,str5);//運行結果創建一個為d:\\1\\a.txt的File對象} }這里有幾個注意點:
1.一個File對象代表硬盤中實際存在的一個文件或者目錄
2.File類構造方法不會給你檢驗這個文件或文件夾是否真實存在,因此無論該路徑下是否存在文件或者目錄,都不影響File對象的創建。
3.創建的是File流對象,并不是已經在你的電腦磁盤上創建了相應的文件或者目錄
4.你給的路徑一定要已經存在,如果你想創建一個d:\a\b\c.txt的File流對象,那么a和b目錄一定要已經存在,否則程序會拋出異常,因為系統找不到指定路徑
5.如果你不指定路徑,那么系統會默認把你想建的文件或者目錄創建在本項目的路徑下
(4)關于相對路徑和絕對路徑:
package untl1; import java.io.File; public class MyFile {public static void main(String[] args) {String str1="d:\\1\\a.txt";File file1=new File(str1);System.out.println(file1.getAbsolutePath());//運行結果:d:\1\a.txtFile file2=new File("b.txt");//這就是項目下的相對路徑System.out.println(file2.getAbsolutePath());//運行結果:C:\Users\86166\IdeaProjects\until\b.txt} }這里有幾點注意事項
1.路徑不區分大小寫
2.路徑分隔符可以是兩個反斜杠\\還可以是一個正斜杠/
3.相對路徑是一個簡化的路徑,絕對路徑是以盤符開頭的路徑
(4)File類的常用方法
| public String getAbsolutePath() | 返回此File的絕對路徑名字符串。 |
| public String getPath() | 將此File轉換為路徑名字符串。 |
| public String getName() | 返回由此File表示的文件或目錄的名稱。 |
| public long length() | 返回由此File表示的文件的長度。 |
| public boolean exists() | 此File表示的文件或目錄是否實際存在。 |
| public boolean isDirectory() | 此File表示的是否為目錄。 |
| public boolean isFile() | 此File表示的是否為文件。 |
| public boolean createNewFile() | 文件不存在,創建一個新的空文件并返回true,文件存在,不創建文件并返回false。 |
| public boolean delete() | 刪除由此File表示的文件或目錄。 |
| public boolean mkdir() | 創建由此File表示的目錄。 |
| public boolean mkdirs() | 創建由此File表示的目錄,包括任何必需但不存在的父目錄。 |
關于常用方法的注意事項
1.我們創建File對象沒有在磁盤上創建相應的文件和目錄,在磁盤上創建用createNewFile()以及mkdir()與mkdirs()
2.如果此File表示目錄,則目錄必須為空才能用delete刪除。
3.mkdirs()和mkdir()方法類似,但mkdir(),只能創建一級目錄,mkdirs()可以創建多級目錄比如//a//b//c
(5)關于目錄的遍歷
先介紹兩種方法:
public String[] list():返回一個String數組,表示該File目錄中的所有子文件或目錄。
public File[] listFiles():返回一個File數組,表示該File目錄中的所有的子文件或目錄。
下面用File[] listFiles()舉個例子:
package untl1; import java.io.File; import java.io.IOException; public class MyFile{public static void main(String[] args)throws IOException{File fp=new File("d:\\1");printF(fp);}static void printF(File fp){System.out.println(fp.getName());if(fp.isDirectory())//如果判斷它是一個目錄{File arr[]=fp.listFiles();//返回所有的子目錄和子文件for(File o:arr)//用for循環進行遍歷{printF(o);}}} } //運行結果是把所有d:\\1目錄下的所有文件和目錄名打印出來再使用File[] listFiles()的注意事項:
1.指定的目錄必須存在
2.指定的必須是目錄。否則容易引發返回數組為null,出現NullPointerException異常
2.I/O流概述
(1)I/O表述:
Java的IO流是實現輸入/輸出的基礎,它可以方便地實現數據的輸入/輸出操作,在Java中把不同的輸入/輸出源(鍵盤、文件、網絡連接等)抽象表述為“流”(stream),通過流的方式允許Java程序使用相同的方式來訪問不同的輸入輸出源。 stream是從起源(source)到接收(sink)的有序數據。Java把所有傳統的流類型(類或抽象類)都放在java.io包中,用以實現輸入輸出功能。
(2)I/O分類:
根據數據的流向分為:
1.輸入流 :把數據從其他設備上讀取到內存中的流。
2.輸出流 :把數據從內存 中寫出到其他設備上的流。
根據數據的類型分為:
1.輸入流 :以字節為單位,讀寫數據的流。
2.輸出流 :以字符為單位,讀寫數據的流。
字節流和字符流的操作方式幾乎完全一樣,區別只是操作的數據單元不同而已。字節
流操作的數據單元是字節,字符流操作的數據單元是字符,Java中一個字符兩個字節,字節流適合讀取視頻,圖片音頻等,字符流適合讀取純文本文件,我們還要必須明確一點的是,一切文件數據(文本、圖片、視頻等)在存儲時,都是以二進制數字的形式保存,都一個一個的字節,那么傳輸時一樣如此。所以,字節流可以傳輸任意文件數據。在操作流的時候,我們要時刻明確,無論使用什么樣的流對象,底層傳輸的始終為二進制數據。
輸入輸出流都是相對于內存而言,從內存中出來就是輸出,到內存中是輸入
(3)四種流類型的祖先(都是繼承Object類):
| 字節流 | 字節輸入流 InputStream | 字節輸出流 OutputStream |
| 字符流 | 字符輸入流 Reader | 字符輸出流 Writer |
(4)I/O流概念模型:
3.字節輸出流(OutputStream)
1.關于OutputStream
所在位置:java.io.OutputStream
簡介:字節輸出流的所有類的超類
2.關于字節輸出流的常用方法:
| public void close() | 關閉此輸出流并釋放與此流相關聯的任何系統資源。 |
| public void flush() | 刷新此輸出流并強制任何緩沖的輸出字節被寫出。 |
| public void write(byte[] b) | 將 b.length個字節從指定的字節數組寫入此輸出流。 |
| public void write(byte[] b, int off, int len) | 從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。 也就是說從off個字節數開始讀取一直到len個字節結束 |
| public abstract void write(int b) | 將指定的字節輸出流。 |
以上五個方法則是字節輸出流都具有的方法,由父類OutputStream定義提供,子類都會共享以上方法
3.FileOutputStream類
(1)FileOutputStream概述:
由于OutputStream是一個抽象類無法實例化對象,那么就需要OutputStream的子類,FileOutputStream是其的一個子類,文件輸出流,用于把數據從內存寫入到文件中
(2)FileOutputStream的構造方法:
構造方法的作用:
- 1.創建一個FileOutputStream的對象
- 2.會根據構造方法傳遞的文件/文件路徑,創建一個空的文件
- 3.會把FileOutputStream的對象指向創建好的文件
(3)那么把數據寫進文件的原理:
我們編寫好的Java程序運行后,Java虛擬機會找操作系統,調用Windows寫數據的方法,然后把數據寫到文件中(由內存--------》寫入磁盤)
java程序——》Jvm(虛擬機)——》OS(操作系統)——》OS調用寫數據方法——》把數據寫入文件中
(4)FileOutputStream的使用步驟:
1.創建一個FileOutputStream的對象,構造方法傳遞寫入數據的目的地
2.調用FileOutputStream實例化對象write方法,把數據寫入文件中
3.釋放資源(流在使用的時候會占用一定的內存資源,使用后關閉會提高程序的效率)
write也分為三種寫入方式:
1.public void write(int b):一個字節一個字節的寫進文件
2.public void write(byte[] b):以一個字節數組的方式寫進文件
3.public void write(byte[] b,int off,int len):寫進以off索引開始len個字節
實例:
package untl1; import java.io.FileOutputStream; import java.io.IOException; public class MyFile{public static void main(String[] args) throws IOException {FileOutputStream file1=new FileOutputStream("d:1\\a.txt");file1.write(97);file1.close();byte arr[]={98,99,100};FileOutputStream file2=new FileOutputStream("d:1\\a.txt");file2.write(arr);file2.close();byte brr[]={101,102,103};FileOutputStream file3=new FileOutputStream("d:1\\a.txt");file3.write(brr,1,2);file3.close();} }整個程序運行下來a.txt最終只會寫進:fg
why?
首先看第一次寫進,注意寫數據的時候會把十進制的97轉換成二進制,因為任意的文本編輯器(記事本等等)在打開的時候,都會查詢編碼表,把字節轉換成字符表示
0~127:查詢ASCII表
其他值:查詢系統默認碼表(中文GBK)這里有個地方需要注意,當我們第一個字節是負數,那么會和后邊的一個字符組成中文顯示比如{-1234,2234,-342,4233,534}就會前兩個組成文字顯示,第三個和第四個會組成漢字顯示,由于第五個不是負數就會按照相應字符顯示
所以第一次就只寫進去一個字符a
那么該第二次寫了,這里注意:在創建輸出流對象的時候,如果你有這個文件,那么會清空文件里邊的數據,如果沒有就新建一個空白文件,所以第二次再寫完后a.txt里邊只有bcd三個字符
同理進行第三次寫文件,最終只寫進了fg
接下來認識一個String的方法:
getBytes():把字符串轉換成字節數組
這樣方便我們把字符串寫進文件
例子:
(5)FileOutputStream實現數據追加續寫、換行
上邊講了,每次創建流對象都會清空文件的數據,那么如何保留目標文件中數據,還能繼續追加新數據呢?使用下邊兩個構造方法:
1、public FileOutputStream(File file, boolean append)
2、public FileOutputStream(String name, boolean append)
這兩個構造方法,第二個參數中都需要傳入一個boolean類型的值,true 表示追加數據,false 表示不追加也就是清空原有數據。這樣創建的輸出流對象,就可以指定是否追加續寫了
在Windows系統中換行是\r\n
我們只需要把換行所代表的字符串寫進文件,即可實現換行功能
例如:
4.字節輸入流(InputStream)
1.關于InputStream
所在位置:java.io.InputStream
簡介:字節輸入流的所有類的超類
2.字節輸入流的常用方法:
| public void close() | 關閉此輸入流并釋放與此流相關聯的任何系統資源。 |
| public abstract int read() | 從輸入流讀取數據的下一個字節。 |
| public int read(byte[] b) | 該方法返回的int值代表的是讀取了多少個字節,讀到幾個返回幾個,讀取不到返回-1 |
以上三個方法則是字節輸入流都具有的方法,由父類InputStream定義提供,子類都會共享以上方法
3.FileInputStream類
(1)FileOutputStream概述:
由于InputStream是一個抽象類無法實例化對象,那么就需要InputStream的子類,FileOutputStream是其的一個子類,文件輸入流,用于從文件種讀取字節
(2)FileInputStream的構造方法
1、FileInputStream(File file): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。
2、FileInputStream(String name): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名name命名。
構造方法的作用:
- 1.創建一個FileInputStream流對象
- 2.會把FileInputStream對象指定構造方法內的文件
(3)讀取數據的原理:
我們編寫好的Java程序運行后,Java虛擬機會找操作系統,調用Windows讀取數據的方法,然后把數據寫到文件中(由磁盤--------》讀入內存)
java程序——》Jvm(虛擬機)——》OS(操作系統)——》OS調用寫數據方法——》把數據寫入文件中
(4)FileInputStream的使用步驟:
1.創建FileInputStream對象,構造方法中綁定要讀取的數據
2.使用FileInputStream對象中的read方法,讀取文件
3.釋放資源
read的兩種讀取方式
這里注意兩種返回值不一樣,第一種方法的返回值是讀取的字節對應的int類型的值,而第二種方法的返回值是所讀取的字節數
每次讀完文件指針會自動往后移動
實例:
這里先介紹String的兩種構造方法:
1.public String(byte bytes[]):給定一個字節數組會把字節數組轉換成字符串
2.public String(byte bytes[], int offset, int length):從下標offest開始讀取length個字節并轉換成字符串
這里的構造方法都有自動解碼的功能,默認編碼utf-8
d:/1/c.txt文件內容:
運行結果:
(5)復制圖片原理:
例子:
1.由于只創建一次輸出流對象所以在寫進文件的時候,寫文件的指針自動后移,所以不必用追加寫的方式創建FileOutputStream對象
2.FileInputStream和FileOutputStream由于都是對文件操作,所以指定的路徑不能是目錄
5.字符流概述
(1)我們在使用字節流的時候,可能會出現一些小問題,就是在遇到中文字符的時候,有時候讀取的時候會顯示亂碼的問題,那是因為我們字節是一個一個讀取,然而一個中文字符會占用幾個字節,假如你一個漢字占用三個字節,你只讀取了其中的兩個字節,那么是不會顯示漢字的,所以亂碼就理所應當了。
盡管字節流也能有辦法決絕亂碼問題,但是還是比較麻煩,于是java就有了字符流,字符為單位讀寫數據,字符流專門用于處理文本文件。如果處理純文本的數據優先考慮字符流,其他情況就只能用字節流了(圖片、視頻、等等只文本例外)。
從另一角度來說:字符流 = 字節流 + 編碼表
字符流的繼承關系:
6.字符輸入流(Reader)
1.關于Reader
所在位置:java.io.Reader
簡介:字符輸入流的所有類的超類
2.字符輸入流的常用方法:
| public void close() : | 關閉此流并釋放與此流相關聯的任何系統資源 |
| public int read() | 從輸入流讀取一個字符 |
| public int read(char[] cbuf) | 從輸入流中讀取一些字符,并將它們存儲到字符數組 cbuf中 |
以上三個方法則是字符輸入流都具有的方法,由父類Reader定義提供,子類都會共享以上方法
3.FileReader類
(1)FileReader類概述:
由于Reader是一個抽象類無法實例化對象,那么就需要Reader的子類,FileReader是其的一個子類,是讀取字符文件的便利類,構造時使用系統默認的字符編碼和默認字節緩沖區
(2)構造方法:
1.FileReader(File file): 創建一個新的 FileReader ,給定要讀取的File對象
2.FileReader(String fileName): 創建一個新的 FileReader ,給定要讀取的文件的字符串名稱
(3)FileReader的使用:
類和FileInputStream類和FileReader用法完全類似包括兩種read讀取和String解碼,只是讀取的單位不同而已
例子:
package untl1; import java.io.FileReader; import java.io.IOException; public class MyFile {public static void main(String[] args) throws IOException {FileReader file1=new FileReader("d:1\\c.txt");int len;while((len=file1.read())!=-1){System.out.println((char)len);}FileReader file2=new FileReader("d:1\\c.txt");int lenn;char arr[]=new char[1024];//注意這里的字符串是charwhile((lenn=file2.read(arr))!=-1){System.out.println(new String(arr));//這里得到new String是把字符數組轉換成字符串,//也可以使用三個參數的,用法與前面的一樣}file1.close();file2.close();} } 運行結果: 誰 還 不 是 個 野 王 誰還不是個野王c.txt內容:
7.字符輸出流(Writer)
1.關于Writer
所在位置:java.io.Writer
簡介:是字符輸入流的所有類的超類(父類),可以讀取字符信息到內存中。它定義了字符輸入流的基本共性功能方法。
2.字符輸出流的常用方法:
| void write(int c) | 寫入單個字符 |
| void write(char[] cbuf) | 寫入字符數組 |
| abstract void write(char[] cbuf, int off, int len) | 寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數 |
| void write(String str) | 寫入字符串 |
| void write(String str, int off, int len) | 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數 |
| void flush() | 刷新該流的緩沖 |
| void close() | 關閉此流,但要先刷新它 |
以上七個方法則是字符輸出流都具有的方法,由父類Writer定義提供,子類都會共享以上方法
3.FileWriter類
(1)FileWriter類概述:
由于Writer是一個抽象類無法實例化對象,那么就需要Writer的子類,FileWriter是其的一個子類,是寫出字符到文件的便利類。構造時使用系統默認的字符編碼和默認字節緩沖區。
(2)構造方法:
1、FileWriter(File file): 創建一個新的 FileWriter,給定要讀取的File對象。
2、FileWriter(String fileName): 創建一個新的 FileWriter,給定要讀取的文件的名稱。
(3)FileWriter的使用:
例子:
注意:關閉資源時,與FileOutputStream不同。 如果不關閉,數據只是保存到緩沖區,并未保存到文件。想要保存到緩沖區就必須關閉資源或者刷新該流的緩沖(就是flush方法)
(4)關閉close和刷新flush
兩者的區別:
flush:刷新緩沖區,流對象可以繼續使用。
close:先刷新緩沖區,然后通知系統釋放資源。流對象不可以再被使用了。
flush()這個函數是清空的意思,用于清空緩沖區的數據流,進行流的操作時,數據先被讀到內存中,然后再用數據寫到文件中,那么當你數據讀完時,我們如果這時調用close()方法關閉讀寫流,這時就可能造成數據丟失,為什么呢?因為,讀入數據完成時不代表寫入數據完成,一部分數據可能會留在緩存區中,這個時候flush()方法就格外重要了。即便是flush方法寫出了數據,操作的最后還是要調用close方法,釋放系統資源。
(5)FileWriter的續寫和換行和前面的字節流續寫和換行一樣的
8. Properties類詳解
(1)Properties概述
是一種java配置文件的類,java.util.Properties繼承于Hashtable,來表示一個持久的屬性集(所以自己也是一個集合)。它使用鍵值結構存儲數據,每個鍵及其對應值都是一個字符串。
(2)Properties常用方法:
| public Object setProperty(String key, String value) | 保存一對屬性 |
| public String getProperty(String key) | 使用此屬性列表中指定的鍵搜索屬性值 |
| public Set stringPropertyNames() | 返回所有鍵的名稱的Set集合 |
(3)Properties常用方法的使用實例:
例子1:
(4)Properties類中store方法:
1.public void store(Writer writer, String comments)
2.public void store(OutputStream out, String comments)
這里注意用第一種store方法可以把集合里的中文寫進去,但是第二種寫入方式不能把集合里邊的中文寫進去,第二個參數用來解釋保存文件是做什么的,不能使用中文,會參生亂碼,默認為Unicode編碼一般都傳的是空字符串“”
方法的作用:把Properties集合里邊的臨時數據持久化寫入磁盤中存儲
使用步驟:
- 1.創建Properties集合對象,添加數據
- 2.創建字節/字符輸出流對象,構造方法綁定要寫進的目的地
- 3.使用 Properties集合中的方法store把集合里邊的臨時數據持久化寫入磁盤中存儲
- 4.釋放資源
運行結果(c.txt變化如下):
第一行是對寫的東西進行解釋,由于傳進的是一個空的字符串所有沒有內容
第二行是默認加的寫入時間
之后就是集合里邊的內容
(5)Properties類中load方法:
1.public void load(InputStream inStream)
2.public void load(Reader reader)
參數的解釋:
InputStream inStream:字節輸入流,不能讀取含有中文的鍵值對
Reader reader:字符輸入流,能讀取含中文的鍵值對
使用步驟:
- 1.創建Properties集合對象
- 2.使用Properties集合對象中的load方法讀取保存鍵值對的文件
- 3.遍歷集合
例子:
package untl1; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Set; public class MyProperties {public static void main(String[] args) throws IOException {Properties myProperties=new Properties();FileReader file1=new FileReader("d:\\1\\c.txt");//里邊保存第(4)點寫進的內容myProperties.load(file1);Set<String> set=myProperties.stringPropertyNames();for (String key:set){System.out.println(key+"="+myProperties.getProperty(key));}} } 運行結果: 劉備=170 關羽=180 張飛=1751.存儲鍵值對的文件中,鍵與值的連接符號可以使用=,空格或者其他符號
2.存儲文件中,可以使用#進行注解,注解的鍵值對不會被讀取
3.存儲價值對的文件中,鍵與值都是字符串不用加引號
9. 緩沖流概述
由于四個基本流(FileInputStream,FileOutputStream,FileReader,FileWriter)的效率比較低,體現在我們多次讀寫文件的時候都要對原始數據多次訪問,每次對原始數據的訪問都會有
java程序——》java虛擬機——》操作系統——》操作系統調用讀寫操作,顯得太麻煩,緩沖流就是在第一次訪問時就把要讀或者要寫的內容存在一個數組中(這個數組就是緩沖流的根本),那么當我們二次訪問時候就可以直接在數組里進行操作
專業點來講就是:緩沖流把數據從原始流成塊讀入或把數據積累到一個大數據塊后再成批寫出,通過減少通過資源的讀寫次數來加快程序的執行。
字節緩沖流:BufferedInputStream,BufferedOutputStream
字符緩沖流:BufferedReader,BufferedWriter
是對四個基本流的加強版
再來看一下四種緩沖流的繼承關系;
10.字節緩沖流(BufferedInputStream,BufferedOutputStream)
1.字節緩沖輸出流(BufferedOutputStream)
(1)構造方法:
1.public BufferedOutputStream(OutputStream out) :創建一個新的緩沖輸入流,注意參數類型為InputStream。
2.public BufferedOutputStream(OutputStream out,int size): 創建一個新的緩沖輸出流,注意size就是自定義緩沖流的數組,不指定就是默認的大小
(2)使用步驟
- 1.創建FileOutputStream對象,構造方法中綁定要輸出的目的地
- 2.創建BufferedOutputStream對象,構造方法為FileFileOutputStream對象,提高FileOutputStream的效率
- 3.使用BufferedOutputStream對象的writer方法,把數據寫入內部緩沖區里邊
- 4.使用BufferedOutputStream里邊的flush方法,把內部緩沖區里邊的數據刷新到文件里
- 5.釋放資源
例子:
package untl1; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class MyProperties {public static void main(String[] args)throws IOException {FileOutputStream file1=new FileOutputStream("d:1\\c.txt");//c.txt是空的文件BufferedOutputStream bos=new BufferedOutputStream(file1);String str="我是哥哥";byte arr[]=str.getBytes();bos.write(arr);bos.flush();bos.close();} } 運行結果: c.txt文件寫進了我是哥哥2.字節緩沖輸入流(BufferedInputStream)
(1)構造方法:
1.public BufferedInputStream(InputStream in) :創建一個新的緩沖輸入流,注意參數類型為InputStream
2.public BufferedInputStream(InputStream in,int size) ::創建一個新的緩沖輸入流,size作用同上
(2)使用步驟:
- 1.創建FileInputStream對象,構造方法中綁定要讀取的數據源
- 2.創建BufferedInputStream對象,構造方法中傳遞FileInputStream對象,提高FileInputStream對象的讀取效率
- 3.使用BufferedInputStream中的方法read方法讀文件
- 4.釋放資源
11.字符緩沖流(BufferedReader,BufferedWriter)
1.字符緩沖輸出流
(1)構造方法:
1.public BufferedWriter(Writer out):創建一個新的緩沖輸入流,注意參數類型為Reader
2.public BufferedWriter(Writer out,int sz):創建一個新的緩沖輸入流,sz作用同上
(2)使用步驟:
- 1.創建字符輸出流對象,構造方法中傳遞字符輸出流對象
- 2.調用字符緩沖輸出流的writer方法,把數據吸入內存緩沖區
- 3.調用字符緩沖輸出流的flush方法,把內存緩沖區的數據刷新到文件中
- 4.釋放資源
例子:
package untl1; import java.io.*; public class MyProperties {public static void main(String[] args)throws IOException {FileWriter fw=new FileWriter("d:1\\c.txt");BufferedWriter bf=new BufferedWriter(fw);String str="我是弟弟";bf.write(new String(str));bf.flush();bf.close();} } 運行結果: 把我是弟弟寫進c.txt文件(3)BufferedWriter特有的方法
public void newLine(): 換行,由系統屬性定義符號
我們以前寫數據的時候把“\r\n”寫進文件就會換行,但是這里可以直接調用這個方法就能實現換行
2.字符緩沖輸入流
(1)構造方法:
1.public BufferedReader(Reader in):創建一個新的緩沖輸入流,注意參數類型為Reader
2.public BufferedReader(Reader in,int sz):創建一個新的緩沖輸入流,sz作用同上
(2)使用步驟:
- 1.創建字符緩沖輸入流對象,構造方法中傳遞字符輸入流
- 2.使用字符緩沖輸入流對象的read方法讀取文本
- 3.釋放資源
(3)BufferedReader特有的方法
public String readLine(): 讀一行數據。 讀取到最后返回null
例子:
package untl1; import java.io.*; public class MyProperties {public static void main(String[] args)throws IOException {FileReader fr=new FileReader("d:1\\c.txt");BufferedReader bf=new BufferedReader(fr);String str1=bf.readLine();System.out.println(str1);String str2=bf.readLine();System.out.println(str2);} } 運行結果: 我是弟弟 null12.緩沖流高效率測試
緩沖流有多高效呢,接下來我們來測試一下,博主把d:0.jpg復制到d:1\\0.copy.jpg,分別用普通流和緩沖流進行比較:
普通流:
緩沖流:
package untl1; import java.io.*; public class MyProperties {public static void main(String[] args)throws IOException {long begin=System.currentTimeMillis();FileInputStream fis=new FileInputStream("d:0.jpg");FileOutputStream fos=new FileOutputStream("d:1\\0copy.jpg");BufferedInputStream bis=new BufferedInputStream(fis);BufferedOutputStream bos=new BufferedOutputStream(fos);int len=0;while((len=bis.read())!=-1){bos.write(len);}bos.flush();bos.close();fis.close();long end=System.currentTimeMillis();System.out.println("整個過程耗時"+(end-begin)+"毫秒");} } 運行結果: 整個過程耗時3毫秒結論:你品,你細品
13.轉換流概述
(1)亂碼問題:
在介紹轉換流之前,不知道大家有沒有遇到一個問題
使用FileReader或者OutputStream讀取txt文件,明明寫的代碼是正確的但是卻讀到一堆亂碼,.
例子:
```cpp package untl1; import java.io.FileReader; import java.io.IOException; public class MyFile {public static void main(String[] args) throws IOException {FileReader file1=new FileReader("d:1\\c.txt");//里邊是幾個漢字int len;while((len=file1.read())!=-1){System.out.println((char)len);}FileReader file2=new FileReader("d:1\\c.txt");int lenn;char arr[]=new char[1024];while((lenn=file2.read(arr))!=-1){System.out.println(new String(arr));}file1.close();file2.close();} } 運行結果: ���為啥呢,往下看
(2)字符編碼和解碼:
我們知道,計算機中儲存的數據都是用二進制數表示的,而我們在屏幕上看到的數字、英文、標點符號、漢字等字符是二進制數轉換之后的結果。按照某種規則,將字符存儲到計算機中,稱為編碼 。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱為解碼 。比如說,按照A規則存儲,同樣按照A規則解析,那么就能顯示正確的文本符號。反之,按照A規則存儲,再按照B規則解析,就會導致亂碼現象。所以開頭的問題就已經明確,當我們使用FileReader或者InputStream進行字符的讀取的時候,解碼時默認為utf-8,我們電腦txt文件默認編碼用ASCII,所以我們只需要改變編碼的方式為utf-8就能把漢字正確的讀取出來(打開文件然后選擇另存為就可以選擇編碼方式如下圖)
編碼和解碼簡單來說:
編碼:字符(能看懂的)------》字節(看不懂的)
解碼:字節(看不懂的)------》字符(能看懂的)
(3)字符編碼和編碼表
1.字符編碼: 就是一套自然語言的字符與二進制數之間的對應規則。
2.z字符集(也叫編碼表):是生活中文字和計算機中二進制的對應規則
字符集的分類:
| ASCII字符集 |
|
| ISO-8859-1字符集: |
|
| GBxxx字符集 |
|
| Unicode字符集 |
|
14. InputStreamReader類和 OutputStreamWriter類
1.InputStreamReader類
(1) 轉換流java.io.InputStreamReader,是Reader的子類,從字面意思可以看出它是從字節流到字符流的橋梁。它讀取字節,并使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。
(2)構造方法:
1.InputStreamReader(InputStream in): 創建一個使用默認字符集的字符流。
2.InputStreamReader(InputStream in, String charsetName): 創建一個指定字符集的字符流。指定的字符集大小寫不限
(3)使用步驟:
- 1.創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表的名稱
- 2.使用InputStreamReader里邊的read方法讀取文件
- 3.釋放資源
例子:
package untl1; import java.io.*; public class MyProperties {public static void main(String[] args)throws IOException {FileInputStream fis=new FileInputStream("d:1\\c.txt");InputStreamReader isr=new InputStreamReader(fis,"utf-8");int len=0;while((len=isr.read())!=-1){System.out.println((char)len);}isr.close();} } 運行結果: 把c.txt文件里的內容按照utf-8標準解析出來注意InputStreamReader構造方法傳進的是字節輸出流
2.OutputStreamWriter類
(1)轉換流java.io.OutputStreamWriter ,是Writer的子類,字面看容易混淆會誤以為是轉為字符流,其實不然,OutputStreamWriter為從字符流到字節流的橋梁。使用指定的字符集將字符編碼為字節。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。
(2)構造方法:
1.OutputStreamWriter(OutputStream in): 創建一個使用默認字符集的字符流。
2.OutputStreamWriter(OutputStream in, String charsetName): 創建一個指定字符集的字符流。指定的字符集大小寫不限
(3)使用步驟:
- 1.創建OutputStreamWriter對象構造方法中傳遞字節輸出流和指定的編碼表名稱
- 2.使用OutputStreamWriter對象中的writer方法,把字符轉換為字節存放在緩沖區
- 3.使用OutputStreamWriter對象中的flush方法,把緩沖區的內容打印到文件上
- 4.釋放資源
例子:
package untl1; import java.io.*; public class MyProperties {public static void main(String[] args)throws IOException {FileOutputStream fos=new FileOutputStream("d:1\\c.txt");OutputStreamWriter osw=new OutputStreamWriter(fos,"utf-8");String str="我是咯咯";osw.write(str);osw.flush();osw.close();} }注意OutputStreamWriter構造方法傳進的是字節輸入流
15.序列化
1.序列化概述
(1)序列化的含義和意義:
序列化機制允許將實現序列化的Java對象轉換成字節序列,這些字節序列可以保存在
磁盤上,或通過網絡傳輸,以備以后重新恢復成原來的對象。序列化機制使得對象可
以脫離程序的運行而獨立存在。對象的序列化(Serialize)指將一個Java對象寫入IO流中,與此對應的是,對象的反序列化(Deserialize)則指從IO流中恢復該Java對象如果需要讓某個對象支持序列化
機制,則必須讓它的類是可序列化的
(2)序列化和反序列化
序列化:Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據、對象的類型和對象中存儲的屬性等信息。字節序列寫出到文件之后,相當于文件中持久保存了一個對象的信息。
反序列化:把字節序列還可以從文件中讀取回來,重構對象,稱為反序列化。對象的數據、對象的類型和對象中存儲的數據信息,都可以用來在內存中創建對象。
2. ObjectOutputStream類
(1)java.io.ObjectOutputStream 類也叫對象的序列化流,將Java對象的原始數據類型寫出到文件,實現對象的持久存儲。
雖然ObjectOutputStream是一個對象的序列化流,但是想要使一個對象序列化還要兩個條件:
1.對象所屬類類必須實現java.io.Serializable 接口(當實現此接口后,就會個給類添加一個標記,如果有的化可以進行序列化和反序列化操作,沒有的話拋出異常)
2.對象所屬類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須注明是瞬態的,使用transient 關鍵字修飾。靜態成員(static)是不能被序列化的
(2)構造方法和特有的方法:
1.構造方法:public ObjectOutputStream(OutputStream out):構造方法傳遞字節輸出流
2.特有的方法:void writeObject(Object obj):將指定的對象寫入序列化流中
(3)ObjectOutputStream的使用步驟:
- 1.創建ObjectOutputStream對象,構造方法傳遞字節輸出流
- 2.使用ObjectOutputStream對象中的writerObject方法,把對象寫入文件
- 3.釋放資源
3 . ObjectInputStream類
(1)java.io.ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復為對象。
(2)構造方法和特有的方法:
1.構造方法:public ObjectInputStream(InputStream in): 注意傳遞的是字節輸入流
2.特有方法:public final Object readObject () : 讀取一個對象。
(3)使用步驟:
- 1.創建ObjectInputStream對象,構造方法傳入字節輸入流
- 2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件
- 3.釋放資源
- 4.使用讀取的對象
例子:
package untl1; import java.io.*; public class MyProperties {public static void main(String[] args) throws IOException,ClassNotFoundException{FileInputStream fis=new FileInputStream("d:1\\c.txt");//只有上一個例子寫入的一個對象ObjectInputStream ois=new ObjectInputStream(fis);Object obj=ois.readObject();ois.close();System.out.println(obj);} } class perosn implements Serializable{private int a;private static int b=12;private transient int c;perosn(){this.a=10;b=100;this.c=1000;}public String toString(){System.out.println("a="+a);System.out.println("b="+b);System.out.println("c="+c);return "";} } 運行結果: a=10 b=12 c=0這個運行結果就印證了
如果有一個屬性不需要可序列化的,則該屬性必須注明是瞬態的,使用transient 關鍵字修飾。靜態成員(static)是不能被序列化的
(4)注意事項:
1.對于JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個 ClassNotFoundException 異常。
2.JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之后發生了修改(就是在反序列化之前修改了類),那么反序列化操作也會失敗,拋出一個InvalidClassException異常。
16.打印流
1.打印流概述:
平時我們在控制臺打印輸出,是調用print和println方法完成的,這兩個方法都來自java.io.PrintStream類,該類能打印各種類型的值是一種便捷的輸出方式,
2.PrintStream類
(1)構造方法:
public PrintStream(File file):輸出的目的地是一個文件
public PrintStream(OutputStream out):輸出的目的地是一個字節輸出流
public PrintStream(String fileName):輸出的目的地是一個文件路徑
(2)PrintStream的特點:
1.只負責數據的輸出,不負責數據的讀取
2.與其他輸入流不同·, PrintStream不會拋出IOException異常
3.有特有的方法print或println,注意沒有printf
(3)PrintStream的使用
1.PrintStream繼承OutputStream類
2.如果使用繼承來自父類的write方法寫數據那么寫入數據的時候會查詢碼表
3.如果使用自己特有的方法print或者println方法寫數據,則會原樣輸出
例子:
package untl1; import java.io.FileNotFoundException; import java.io.PrintStream; public class MyProperties {public static void main(String[] args) throws FileNotFoundException {PrintStream ps=new PrintStream("D:1\\c.txt");//c.txt是空白文件ps.print(97);ps.write(97);} } 運行結果: 在c.txt文件里的第一行內容為:a97打印流還有更神奇的操作,那就是改變輸出語句的目的地(打印流的流向)System.setOut方法改變輸出語句的目的地為參數中傳遞的打印流的目的地
static void setOut(PrintStream our):重新分配標準輸出流
例子:
package untl1; import java.io.FileNotFoundException; import java.io.PrintStream; public class MyProperties {public static void main(String[] args) throws FileNotFoundException {PrintStream ps=new PrintStream("D:1\\c.txt");//c.txt是空文件System.out.println("heello world");System.setOut(ps);System.out.println("哈哈哈");} } 運行結果: hello world哈哈哈則是被輸出到c.txt文件中
總結
以上是生活随笔為你收集整理的三万字的java I/O流基础总结看完肯定能把女朋友教会的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java的两种运行方式Applet和Ap
- 下一篇: 给我十分钟带你过完java多线程所有基础