【java】I/O流

love_Aym發表於2018-04-11

參考:https://blog.csdn.net/qq_32451699/article/details/52230963 ——基本理解

進階理解:

FilterInputStream 與 裝飾者模式:https://blog.csdn.net/zhao123h/article/details/52826306

FilterInputStream 與 裝飾者模式:https://blog.csdn.net/zhao123h/article/details/52826682  




一、概念

    * IO流用來處理裝置之間的資料傳輸

    * Java對資料的操作是通過流的方式

    * Java用於操作流的類都在IO包中

    * 流按流向分為兩種:輸入流,輸出流。

    * 流按操作型別分為兩種:

        * 位元組流 :位元組流可以操作任何資料,因為在計算機中任何資料都是以位元組的形式儲存的

        * 字元流 :字元流只能操作純字元資料,比較方便。

二、IO流常用父類

    * 位元組流的抽象父類:

        *InputStream

        *OutputStream

    * 字元流的抽象父類:

        * Reader

        * Writer       

三、IO程式書寫

    * 使用前,匯入IO包中的類

    * 使用時,進行IO異常處理

    * 使用後,釋放資源

四、FileInputStream

* read()一次讀取一個位元組

*

        FileInputStreamfis = new FileInputStream("aaa.txt");   //建立一個檔案輸入流物件,並關聯aaa.txt

        int b;                                                  //定義變數,記錄每次讀到的位元組

        while((b= fis.read()) != -1) {                         //將每次讀到的位元組賦值給b並判斷是否是-1

            System.out.println(b);                              //列印每一個位元組

        }      

        fis.close();                                            //關閉流釋放資源

* read()方法返回值為什麼是int

* read()方法讀取的是一個位元組,為什麼返回是int,而不是byte

*

        因為位元組輸入流可以操作任意型別的檔案,比如圖片音訊等,這些檔案底層都是以二進位制形式的儲存的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111

        那麼這11111111是byte型別的-1,我們的程式是遇到-1就會停止不讀了,後面的資料就讀不到了,所以在讀取的時候用int型別接收,如果11111111會在其前面補上

        24個0湊足4個位元組,那麼byte型別的-1就變成int型別的255了這樣可以保證整個資料讀完,而結束標記的-1就是int型別

五、FileOutputStream

* write()一次寫出一個位元組

*

        FileOutputStreamfos = new FileOutputStream("bbb.txt"); //如果沒有bbb.txt,會建立出一個

        //fos.write(97);                        //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte

        fos.write(98);

        fos.write(99);

        fos.close();

* FileOutputStream追加

* A:案例演示

    *FileOutputStream的構造方法寫出資料如何實現資料的追加寫入

*

        FileOutputStreamfos = new FileOutputStream("bbb.txt",true);    //如果沒有bbb.txt,會建立出一個

        //fos.write(97);                        //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte

        fos.write(98);

        fos.write(99);

        fos.close();


* 拷貝圖片

* FileInputStream讀取

* FileOutputStream寫出


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Demo1_FileInputStream {
	/**
	 * @param args
	 * @throws IOException  
	 * read()方法讀取的是一個位元組,為什麼返回是int,而不是byte
	 * 
	 * 00010100 00100100 01000001 11111111 0000000
	 * 
	 * 10000001    byte型別-1的原碼
	 * 11111110    -1的反碼
	 * 11111111    -1的補碼
	 * 
	 * 00000000 00000000 00000000 11111111
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		FileInputStream fis = new FileInputStream("xxx.txt");	//建立流物件
		int b;
		while((b = fis.read()) != -1) {
			System.out.println(b);
		}
		
		fis.close();   //標準格式
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("xxx.txt");	//建立流物件
		int x = fis.read();										//從硬碟上讀取一個位元組
		System.out.println(x);
		int y = fis.read();
		System.out.println(y);
		int z = fis.read();
		System.out.println(z);
		int a = fis.read();
		System.out.println(a);
		int b = fis.read();
		System.out.println(b);
		fis.close();											//關流釋放資源
	}

}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo2_FileOutputStream {
	/**
	 * @param args
	 * @throws IOException 
	 * FileOutputStream在建立物件的時候是如果沒有這個檔案會幫我建立出來,如果有這個檔案就會先將檔案清空
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		FileOutputStream fos = new FileOutputStream("yyy.txt",true);	//如果想續寫就在第二個引數傳true
		fos.write(97);
		fos.write(98);
		
		fos.close();  //標準格式
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileOutputStream fos = new FileOutputStream("yyy.txt");		//建立位元組輸出流物件,如果沒有就自動建立一個
		//fos.write(97);				//雖然寫出的是一個int數,但是到檔案上的是一個位元組,會自動去除前三個8位
		//fos.write(98);
		//fos.write(99);
		fos.write(100);
		fos.close();
	}
}



拷貝檔案的四種方式:

1、一個位元組一個位元組讀寫--效率低(不推薦)

2、大陣列讀寫--記憶體溢位(不推薦)

3、小陣列讀寫--推薦

4、緩衝區

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo3_Copy {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//demo2();
		//demo3();
	}

	public static void demo3() throws FileNotFoundException, IOException {
		//第二種拷貝,不推薦使用,因為有可能會導致記憶體溢位
		FileInputStream fis = new FileInputStream("致青春.mp3");		//建立輸入流物件,關聯致青春.mp3
		FileOutputStream fos = new FileOutputStream("copy.mp3");	//建立輸出流物件,關聯copy.mp3
		//int len = fis.available();
		//System.out.println(len);
		
		byte[] arr = new byte[fis.available()];						//建立與檔案一樣大小的位元組陣列
		fis.read(arr);												//將檔案上的位元組讀取到記憶體中
		fos.write(arr);												//將位元組陣列中的位元組資料寫到檔案上
		
		fis.close();
		fos.close();
	}

	public static void demo2() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("致青春.mp3");		//建立輸入流物件,關聯致青春.mp3
		FileOutputStream fos = new FileOutputStream("copy.mp3");	//建立輸出流物件,關聯copy.mp3
		
		int b;
		while((b = fis.read()) != -1) {								//在不斷的讀取每一個位元組
			fos.write(b);											//將每一個位元組寫出
		}
		
		fis.close();												//關流釋放資源
		fos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("雙元.jpg");		//建立輸入流物件,關聯雙元.jpg
		FileOutputStream fos = new FileOutputStream("copy.jpg");	//建立輸出流物件,關聯copy.jpg
		
		int b;
		while((b = fis.read()) != -1) {								//在不斷的讀取每一個位元組
			fos.write(b);											//將每一個位元組寫出
		}
		
		fis.close();												//關流釋放資源
		fos.close();
	}
}


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo4_ArrayCopy {

	/**
	 * @param args
	 * 第三種拷貝: 定義小陣列,標準格式
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//demo2();
		FileInputStream fis = new FileInputStream("致青春.mp3");
		FileOutputStream fos = new FileOutputStream("copy.mp3");
		
		byte[] arr = new byte[1024 * 8];
		int len;
		while((len = fis.read(arr)) != -1) {	//如果忘記加arr,返回的就不是讀取的位元組個數,而是位元組的碼錶值
			fos.write(arr,0,len);
		}
		
		fis.close();
		fos.close();
	}

	public static void demo2() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("xxx.txt");
		FileOutputStream fos = new FileOutputStream("yyy.txt");
		
		byte[] arr = new byte[2];
		int len;
		while((len = fis.read(arr)) != -1) {
			fos.write(arr,0,len);
		}
		
		fis.close();
		fos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("xxx.txt");
		byte[] arr = new byte[2];
		int a = fis.read(arr);						//將檔案上的位元組讀取到位元組陣列中
		
		System.out.println(a);						//讀到的有效位元組個數
		for (byte b : arr) {						//第一次獲取到檔案上的a和b
			System.out.println(b);
		}
		System.out.println("-----------------------");
		int c = fis.read(arr);
		System.out.println(c);
		for (byte b : arr) {
			System.out.println(b);
		}
		fis.close();
	}
}
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo5_BufferCopy {
	/**
	 * @param args
	 * @throws IOException 
	 * close方法: 具備重新整理的功能,在關閉流之前,就會先重新整理一次緩衝區,將緩衝區的位元組全都重新整理到檔案上,再關閉,close方法刷完之後就能寫了
	 * flush方法:具備重新整理的功能,刷完之後還可以繼續寫
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//flush和close方法的區別
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("致青春.mp3"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.mp3"));
		
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}
		bis.close();
		bos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("致青春.mp3");			//建立輸入流物件,關聯致青春.mp3
		FileOutputStream fos = new FileOutputStream("copy.mp3");		//建立輸出流物件,關聯copy.mp3
		BufferedInputStream bis = new BufferedInputStream(fis);			//建立緩衝區物件,對輸入流進行包裝讓其變得更加強大
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}
		
		bis.close();  //只關閉裝飾後的物件即可
		bos.close();
	}
}

小陣列的讀寫和帶Buffered的讀取哪個更快?

    * 定義小陣列如果是8192個位元組大小和Buffered比較的話

    * 定義小陣列會略勝一籌,因為讀和寫操作的是同一個陣列

    * 而Buffered操作的是兩個陣列

flush和close方法的區別

* flush()方法

    * 用來重新整理緩衝區的,重新整理後可以再次寫出

* close()方法

    * 用來關閉流釋放資源的的,如果是帶緩衝區的流物件的close()方法,不但會關閉流,還會再關閉流之前重新整理緩衝區,關閉後不能再寫出

六、字元流

位元組流讀寫中文)

* 位元組流讀取中文的問題

    * 位元組流在讀中文的時候有可能會讀到半個中文,造成亂碼

* 位元組流寫出中文的問題

    * 位元組流直接操作的位元組,所以寫出中文必須將字串轉換成位元組陣列

    * 寫出回車換行 write("\r\n".getBytes());






相關文章