IO流(上)


IO流 (上)

1.理解:IO流即Input流和Output流;
輸入流:外圍設備——>核心處理器;
輸出流:核心處理器——>外圍設備;

總之:以內存爲中心。

2.作用:用來處理設備之間的數據傳輸;設備又分爲輸入設備和輸出設備;
3.字節流和字符流:
字節流:處理的數據都是字節;
字符流:由來:早期的字節流和編碼表;
作用:爲了更便於對文字數據的操作;在內部可以融合編碼表。
體系技巧:該體系中的子類對象中,後綴名都是父類名稱,前綴名都是該流對象的功能名稱。

4.字節流的抽象基類:InputStream和OutputStream ;
5.字符流的抽象基類:Reader和Writer;
讀——>輸入; 寫——>輸出

操作文件中的數據:
1. 寫:將字符串寫入到指定文件中;
1.創建輸出流對象;對象一建立就會將指定的文件創建出來,若存在同名文件,則被覆蓋;
2.通過調用write方法來寫入數據;該數據被寫入到了緩衝區中;
3.通過調用flush()方法刷新流對象。將緩衝區的數據寫入到目的地中;
4.通過調用close()方法將流對象關閉,但關閉之前會刷新流。

代碼體現:

			FileWriter fw=new FileWriter("c:\\jdk.txt");
			fw.write("abscds");
			fw.flush();
			fw.close();

flush和close方法的區別:
flush():刷新流對象,流沒有關閉; close():刷新流對象且關閉流。

IO異常的處理方式:
1.在創建輸出流對象時,可能路徑不存在,所以會拋異常;
2.寫數據時可能磁盤空間不足,仍會拋異常;
3.關閉資源時,可能關閉失敗,拋異常;
4.所以將這三句使用try...catch,將異常捕獲;
5.但如果對象創建失敗,就不能再調用close方法即不能關閉流對象;而使用完資源後必須關閉資源,所以將close放在finally語句塊中;
6.在finally語句塊中仍然需要拋異常;
7.對象變量名在try語句塊中,則只能在try中使用,finally中就不能使用,則不能調用close方法;所以將變量定義在try外,將其初始化爲空;

8.如果流對象創建失敗,則一直爲空,就不能調用close方法,則發生空指針異常;所以要判斷到底是否爲空,不爲空再調用close方法。

代碼體現如下:

		FileWriter fw = null;
		try {
			fw = new FileWriter("demo.txt",true);			
			fw.write("hello"+LINE_SPARATOR+"world");
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally {
			if (fw != null)
				try {
					fw.close();
				} catch (IOException e) {

					throw new RuntimeException("關閉失敗");
				}
		}


小細節;1.續寫文件中的內容:通過構造函數FileWriter(String,boolean):boolean 爲真則續寫;
2.將文件中的內容換行:

		private static final String LINE_SEPARATOR=System.getProperty(line.separator);//獲取當前系統的換行符
	 	       fw.write("Hello"+LINE_SEPARATOR+"World");

2.讀:將指定文件的內容讀取並打印出來;

第一種方式:通過read()讀取單個字符,返回int,碼值,若到結束標記則返回-1;

			FileReader fr=new FileReader("d:\\demo.java");//對象一建立,就必須要明確被讀取的文件
			int i=0;//定義一個變量表示讀取後的數值
			while((i=fr.read())!=-1) {
				System.out.println((char)i); //打印i所對應的字符 
			}
			fr.close();

第二種方式:通過read(char[] chs)將讀取到的字符存入到字符數組中,返回讀取的字符個數,若到結束標記則返回-1;

			FileReader fr=new FileReader("d:\\demo.java");//對象一建立,就必須要明確被讀取的文件
			int len=0;//定義一個變量表示讀取的字符個數
			char[] chs = new char[1024];//定義字符數組存儲讀取的字符,長度爲2kb,因爲一個字符2字節;
			while((len=fr.read(chs))!=-1) {
				System.out.println(new String(chs,0,len)); //打印字符數組中的"有效字符" 
			}
			fr.close();


注意:如果在 char[] chs = new char[3];//若字符串爲abcdeint len1=fr.read(chs);則此時,讀取到的len1爲3,讀取到的內容是abc;若再 int len2=fr.read(chs);此時因數組長度至始至終都爲3,從d開始 讀,d覆蓋a,讀完e就遇到結束標記,而此時e就將b覆蓋了,所以最終數組中的三個元素時dec;若再 int len3=fr.read(chs);此時已經讀到結束標記了,所以返回-1.而chs中的元素仍然是dec.

3.複製文件的原理:從指定文件中讀取文件的數據,將讀取到的數據寫入到另一個目的地。

6.字符流的緩衝區

1.好處:提高了對字符流讀寫數據的效率;若流不存在,則緩衝區存在沒有意義;
2.對應抽象基類:BufferedWriter;BufferedReader
3.原理:將數據進行存儲到數組中,字符流——>字符數組
4.方法:緩衝區中的寫方法都是將數據寫入到緩衝區中,讀方法是從內存中讀數據;
close():內部調用的是流對象中的close()方法,所以關閉緩衝區即關閉流;
newLine():內部調用System.getProperty("line.separator");獲取系統的換行符;是緩衝區對象才能使用,特有方法。
5.BufferedReader 類:該類對象一建立,就創建了一個字符數組,默認長度爲8192,同時多了一個提高行的效率;
read():讀內存中的數據 ;而流對象中的read方法是從硬盤讀數據;
readLine():讀取一行文本,返回行內容,不返回行終止符,若到了末尾,則返回null;

readLine方法原理:內部調用了BufferedReader中的read方法,讀到行終止符之前,將緩衝區中讀取出來的字符臨時存儲,直到讀到行終止符,將臨時存儲的數據轉成字符返回。
6.緩衝區的基本思想,提高效率的原理?
緩衝區的基本思想就是對要處理的數據進行臨時存儲。譬如購物車以及籃子。
原理:減少頻繁的操作,給讀取流對象和寫入流對象提供中轉站,相對於來回跑的麻煩,利用緩衝區的容量,可以一邊先存儲,滿了後再寫入的方式, 這樣就提高了效率。

7.緩衝區的原理分析:緩衝區一建立就已創建一個數組;

緩衝區中的read()方法:內部調用流的read([])方法,將硬盤上讀出來的一部分數據到緩衝區的數組中;若緩衝區的數組中有數據,則調用read()方法將數組中的元素一個一個的取出。
readLine():基於read()方法,read方法將緩衝區數組中的元素一個一個取出,當識別到數組中的元素爲行終止符時,則不再取元素,將之前的元素取出打印,再去識別數組中的元素。

8.裝飾設計模式:

對一組對象進行功能的增強,職責的增強,還不改變原有對象(並不建議繼承,否則體系逐漸龐大,不利於擴展和維護)。
建議;建立另一個類,持有原對象的引用,即與源對象相關聯,對原對象進行裝飾,比繼承更靈活;
記住:被裝飾類和裝飾類必須屬於同一個體系。

9.LineNumberReader 類:

BufferedReader 的子類,返回文本行,已定義了方法setLineNumber(int)和getLineNumber(),可分別用於設置和獲取當前行號;默認 行標號從0開始 ,行號隨數據讀取在每個行結束符遞增,還可以更改行號;若讀完了返回null。
getLineNumber():獲取行號;

10.字節流:什麼數據都能處理;
InputStream OutputStream
FileOutputStream演示:

		//1.自定義緩衝區數組 :複製mp3文件
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		byte[] by=new byte[1024];
		int ch=0;
		while((ch=fis.read())!=-1){
			fos.write(by,0,ch);
		}
		fis.close();
		fos.close();

		//2.使用available()創建長度剛剛好的數組;
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		byte[] by=new byte[fis.available()];
		int ch=0;
		while((ch=fis.read())!=-1){
			fos.write(by,0,ch);
		}
		fis.close();
		fos.close();

		//3.使用緩衝區複製
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		BufferedInputStream bis=new BufferedInputStream(fis);
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		BufferedOutputStream bos=new BufferedOutputStream(fos);
		int by=0;
		while((by=bis.read())!=-1){
			bos.write(by);
		}
		bis.close();
		bos.close();

		//4.不使用緩衝區
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		int ch=0;
		while((ch=fis.read())!=-1){
			fos.write(ch);
		}
		fis.close();
		fos.close();

開發時,建議使用第一種;

11.字節流和字符流讀取區別:
字節流:一次只能讀一個字節,半個中文;
字符流:一次能讀兩個字節,一個字符,一箇中文;

注意:使用字符流不可以複製圖片,因爲字符流就是字節流+編碼表,而用字符流去複製圖片時,字符流會默認將圖片的字節碼格式進行編碼,這樣可能會導致 複製後的圖片與原圖不一致。

12.字節流和字符流的橋樑:轉換流,將字節流和編碼表進行了封裝,提供了對字符操作的更便捷方式。

由來:字節流讀取中文,先將中文讀取到字節數組中,通過String類的getBytes()方法將字節數組中的元素轉爲字符串,但這樣不能讀取單箇中文,要讀取 單箇中文還得通過toCharArray()方法將其轉爲數組;太過麻煩;所以引出字節流和字符流的橋樑——>InputStreamReader,OutputStreamWriter.

轉換流的兩個橋樑都是從哪裏到哪裏?
首先將文件通過InputStreamReader的方式將字節流數據轉成字符流,爲了高效,將其先存儲到緩衝區中;
然後通過OutputStreamWriter將緩衝區中的字符數據轉成字節,最後輸出。

			FileReader fr=new FileReader("XXX");

			FileInputStream fis=new FileInputStream("XXX");
			InputStreamReader isr=new InputStreamReader(fis);

上面三句話,第一句是第二句和第三句話的封裝;FileReader是InputStreamReader類的子類,因爲只有有了轉換流,對字節進行查表編碼,纔可以讀取字符,所以FileReader方法都是來自轉換流轉化後的讀寫方法。

子父類的區別:FileReader是用於操作文本文件使用默認編碼表的便捷類,因爲它將字節流和編碼表進行封裝;如果操作的不是文件且不是默認編碼表, 就不能用RileReader類操作文件,而是用轉換流,通過傳入的具體字節流對象來確定指定操作的數據,而且還可以傳入指定要使用的編碼 表。

便捷類弊端 :因其是將文件、字節流和默認編碼表封裝,所以只能操作文件,而且只能使用默認編碼表。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章