一、FileInputStream
1、FileInputStream 類概述
java.io.FileInputStream 類是文件輸入流,從文件中讀取數據,讀取到內存中使用。
FileInputStream 可用於字符文件或非字符文件的輸入,因為所有的文件都是由字節組成的。
2、FileInputStream 類繼承結構
3、構造方法
FileInputStream(File file) : 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。
FileInputStream(String name) : 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名 name命名。
參數:讀取文件的數據源
String name:文件的路徑
File file:文件對象
構造方法的作用:
① 會創建一個FileInputStream對象
② 會把FileInputStream對象指定構造方法中要讀取的文件
讀取數據的原理(硬盤--> 內存)
java程序-->JVM-->OS-->OS讀取數據的方法-->讀取文件
字節輸入流的使用步驟【重要】:
① 創建FileInputStream對象,構造方法中綁定要讀取的數據源
② 使用FileInputStream對象中的方法read,讀取文件
③ 釋放資源
二、常用方法
int read()
從輸入流中讀取數據的下一個字節。 返回 0 到 255 范圍內的 int 字節值。 如果因為已經到達流末尾而沒有可用的字節, 則返回值 -1。
int read(byte[] b)
從此輸入流中將最多 b.length 個字節的數據讀入一個 byte 數組中。 如果因為已經到達流末尾而沒有可用的字節, 則返回值 -1。 否則以整數形式返回實際讀取的字節數。
int read(byte[] b, int off,int len)
將輸入流中最多 len 個數據字節讀入 byte 數組。 嘗試讀取 len 個字節, 但讀取的字節也可能小於該值。 以整數形式返回實際讀取的字節數。 如果因為流位於文件末尾而沒有可用的字節, 則返回值 -1。
public void close() throws IOException
關閉此輸入流並釋放與該流關聯的所有系統資源。
三、案例
1、讀取文件的值
代碼實現:
1 @Test 2 public void testFileInputStream() { 3 FileInputStream fileInputStream = null; 4 try { 5 //1. 實例化File類的對象,指明要操作的文件 6 File file = new File("hello.txt"); 7 8 //2.提供具體的流 9 fileInputStream = new FileInputStream(file); 10 11 //3. 數據的讀入 12 int data = fileInputStream.read(); 13 while (data != -1) { 14 System.out.print((char)data); 15 data= fileInputStream.read(); 16 } 17 } catch (IOException e) { 18 e.printStackTrace(); 19 } finally { 20 //4. 流的關閉操作 21 try { 22 if (fileInputStream != null) { 23 fileInputStream.close(); 24 } 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } 28 } 29 }
當文件中沒有中文的時候,運行結果如下:
當文件中出現中文時:
原文件:
控制台輸出:
這個時候竟然輸出亂碼了,為什么呢?(下面解釋)
2、使用 read() 的重載方法讀取文件
代碼實現:
1 @Test 2 public void testFileInputStream1() { 3 FileInputStream fileInputStream = null; 4 try { 5 //1. 實例化File類的對象,指明要操作的文件
6 File file = new File("hello.txt"); 7
8 //2.提供具體的流
9 fileInputStream = new FileInputStream(file); 10
11 //3. 數據的讀入
12 byte[] buffer = new byte[5]; 13 int len;//記錄每次讀取的字節的個數
14 while((len = fileInputStream.read(buffer)) != -1){ 15 String str = new String(buffer,0,len); 16 System.out.print(str); 17
18 } 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } finally { 22 //4. 流的關閉操作
23 try { 24 if (fileInputStream != null) { 25 fileInputStream.close(); 26 } 27 } catch (IOException e) { 28 e.printStackTrace(); 29 } 30 } 31 }
當讀取的文件中沒有中文時,也是正常的。
可是當文件中有中文時:
這個時候又出現亂碼了!!!
3、為什么會出現亂碼呢?
這是因為英文和中文的字符集不同的原因。
英文情況下,無論是 ASCII編碼還是 UTF-8編碼,一個字母都會占一個字節。
中文情況下,使用的 UTF-8 編碼,這個文字就會占用 三個字節。
(1)情況一:使用 read() 一個個讀取
① 當讀取英文時:
會一個個字節去讀,而一個英文正好對應一個字節。
② 當包含中文時:
由於里面包含中文,一個中文占用三個字節,一個個字節去讀取的時候,會把一個中文拆分為三個字節,依次顯示出來,就呈現這樣的效果。
(2)情況二:使用 read(Char[] cbuf) 讀取
① 當讀取英文時:
使用字節數組讀取時,英文也正好可以讀取顯示。
② 當讀取中文時:
使用字節數組讀取時,會把中文拆分讀取,然后進行顯示。
最后運行結果:
4、使用字節數組讀取
read(byte[] b) ,每次讀取b的長度個字節到數組中,返回讀取到的有效字節個數,讀取到末尾時,返回 -1 。
int read(byte[] b) 從輸入流中讀取一定數量的字節,並將其存儲在緩沖區數組 b 中。
明確兩件事情:
a. 方法的參數byte[]的作用?
起到緩沖作用,存儲每次讀取到的多個字節,數組的長度一把定義為1024(1kb)或者1024的整數倍
b.方法的返回值int是什么?
每次讀取的有效字節個數
Demo:
1 public static void main(String[] args) throws IOException { 2 //創建FileInputStream對象,構造方法中綁定要讀取的數據源
3 FileInputStream fis = new FileInputStream("E:\\b.txt"); 4 //使用FileInputStream對象中的方法read讀取文件
5 //int read(byte[] b) 從輸入流中讀取一定數量的字節,並將其存儲在緩沖區數組 b 中。
6 /* 7 發現以上讀取時一個重復的過程,可以使用循環優化 8 不知道文件中有多少字節,所以使用while循環 9 while循環結束的條件,讀取到-1結束 10 */
11 byte[] bytes = new byte[1024];//存儲讀取到的多個字節
12 int len = 0; //記錄每次讀取的有效字節個數
13 while((len = fis.read(bytes))!=-1){ 14 //String(byte[] bytes, int offset, int length) 把字節數組的一部分轉換為字符串 offset:數組的開始索引 length:轉換的字節個數
15 System.out.println(new String(bytes,0,len)); 16 } 17
18 //釋放資源
19 fis.close(); 20 }
Tips:使用數組讀取,每次讀取多個字節,減少了系統間的IO操作次數,從而提高了讀寫的效率,建議開發中使用。
字節流讀取文件的原理:
四、復制文件
復制文件原理圖解:
文件復制的步驟:
1. 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源
2. 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地
3. 使用字節輸入流對象中的方法read讀取文件
4. 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中
5. 釋放資源;
代碼實現:
1 public static void main(String[] args) throws IOException { 2 //1.創建一個字節輸入流對象,構造方法中綁定要讀取的數據源
3 FileInputStream fis = new FileInputStream("c:\\1.jpg"); 4 //2.創建一個字節輸出流對象,構造方法中綁定要寫入的目的地
5 FileOutputStream fos = new FileOutputStream("d:\\1.jpg"); 6 //一次讀取一個字節寫入一個字節的方式
7 //3.使用字節輸入流對象中的方法read讀取文件
8 /*int len = 0; 9 while((len = fis.read())!=-1){ 10 //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中 11 fos.write(len); 12 }*/
13
14 //使用數組緩沖讀取多個字節,寫入多個字節
15 byte[] bytes = new byte[1024]; 16 //3.使用字節輸入流對象中的方法read讀取文件
17 int len = 0;//每次讀取的有效字節個數
18 while((len = fis.read(bytes))!=-1){ 19 //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中
20 fos.write(bytes,0,len); 21 } 22
23 //5.釋放資源(先關寫的,后關閉讀的;如果寫完了,肯定讀取完畢了)
24 fos.close(); 25 fis.close(); 26 }
注意:流的關閉原則,先開后關,后開先關。
五、注意點
1、對於文本文件(.txt,.java,.c,.cpp),使用字符流處理。
2、對於非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字節流處理。
3、使用字節流FileInputStream處理文本文件,可能出現亂碼。