您好,登錄后才能下訂單哦!
這篇文章主要介紹“java的FileInputStream流如何使用”,在日常操作中,相信很多人在java的FileInputStream流如何使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”java的FileInputStream流如何使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
JAVA中針對文件的讀寫操作設置了一系列的流,其中主要有FileInputStream,FileOutputStream,FileReader,FileWriter四種最為常用的流
FileInputStream流被稱為文件字節輸入流,意思指對文件數據以字節的形式進行讀取操作如讀取圖片視頻等
2.1)通過打開與File類對象代表的實際文件的鏈接來創建FileInputStream流對象
public FileInputStream(File file) throws FileNotFoundException{}
若File類對象的所代表的文件不存在;不是文件是目錄;或者其他原因不能打開的話,則會拋出FileNotFoundException
/** * * 運行會產生異常并被撲捉--因為不存在xxxxxxxx這樣的文件 */ public static void main(String[] args) { File file=new File("xxxxxxxx"); //根據路徑創建File類對象--這里路徑即使錯誤也不會報錯,因為只是產生File對象,還并未與計算機文件讀寫有關聯 try { FileInputStream fileInputStream=new FileInputStream(file);//與根據File類對象的所代表的實際文件建立鏈接創建fileInputStream對象 } catch (FileNotFoundException e) { System.out.println("文件不存在或者文件不可讀或者文件是目錄"); } }
2.2)通過指定的字符串參數來創建File類對象,而后再與File對象所代表的實際路徑建立鏈接創建FileInputStream流對象
public FileInputStream(String name) throws FileNotFoundException
通過查看源碼,發現該構造方法等于是在第一個構造方法的基礎上進行延伸的,因此規則也和第一個構造方法一致
public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); }
2.3)該構造方法沒有理解---查看api是指使用的fdObj文件描述符來作為參數,文件描述符是指與計算機系統中的文件的連接,前面兩個方法的源碼中最后都是利用文件描述符來建立連接的
public FileInputStream(FileDescriptor fdObj)
3.1)從輸入流中讀取一個字節返回int型變量,若到達文件末尾,則返回-1
public int read() throws IOException
理解讀取的字節為什么返回int型變量
1、方法解釋中的-1相當于是數據字典告訴調用者文件已到底,可以結束讀取了,這里的-1是Int型
2、那么當文件未到底時,我們讀取的是字節,若返回byte類型,那么勢必造成同一方法返回類型不同的情況這是不允許的
3、我們讀取的字節實際是由8位二進制組成,二進制文件不利于直觀查看,可以轉成常用的十進制進行展示,因此需要把讀取的字節從二進制轉成十進制整數,故返回int型
4、 因此結合以上3點,保證返回類型一致以及直觀查看的情況,因此該方法雖然讀取的是字節但返回int型
read方法讀取實例--最后輸出內容和字符內容一致是123
package com.test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class FileStream { /** * * */ public static void main(String[] args) { //建立文件對象 File file=new File("C:\\Users\\Administrator\\Desktop\\1.txt"); try { //建立鏈接 FileInputStream fileInputStream=new FileInputStream(file); int n=0; StringBuffer sBuffer=new StringBuffer(); while (n!=-1) //當n不等于-1,則代表未到末尾 { n=fileInputStream.read();//讀取文件的一個字節(8個二進制位),并將其由二進制轉成十進制的整數返回 char by=(char) n; //轉成字符 sBuffer.append(by); } System.out.println(sBuffer.toString()); } catch (FileNotFoundException e) { System.out.println("文件不存在或者文件不可讀或者文件是目錄"); } catch (IOException e) { System.out.println("讀取過程存在異常"); } } }
3.2)從輸入流中讀取b.length個字節到字節數組中,返回讀入緩沖區的總字節數,若到達文件末尾,則返回-1
public int read(byte[] b) throws IOException
1. 我們先設定一個緩沖區即字節數組用于存儲從流中讀取的字節數據,該數組的長度為N
2. 那么就是從流中讀取N個字節到字節數組中。但是注意返回的是讀入的總字節數而并不是N,說明有的時候實際讀入的總字節數不一定等于數組的長度
3. 文件的內容是12345.那么流中一共有5個字節,但是我們設定的字節數組長度為2.那么會讀取幾次?每次情況是怎么樣的?
public class FileStream { public static void main(String[] args) { //建立文件對象 File file=new File("C:\\Users\\Administrator\\Desktop\\1.txt"); try { //建立鏈接 FileInputStream fileInputStream=new FileInputStream(file); int n=0; byte[] b=new byte[2]; int i=0; while (n!=-1) //當n不等于-1,則代表未到末尾 { n=fileInputStream.read(b);//返回實際讀取到字節數組中的字節數 System.out.println(n); System.out.println(Arrays.toString(b)); //讀取后的字節數組內容 i++; System.out.println("執行次數:"+i); } System.out.println(new String(b)); } catch (FileNotFoundException e) { System.out.println("文件不存在或者文件不可讀或者文件是目錄"); } catch (IOException e) { System.out.println("讀取過程存在異常"); } } }
實際執行結果如下:
可以看出,數組長度為2,因此第一次讀取2個字節到數組中,數組已經被填滿。流中還剩余3個字節繼續讀取
第二次讀取,仍然讀取2個字節到數組中,數組內容被替換。此時流中只剩余1個字節,根據API說明,讀取數組長度(2)個字節到數組中,但接下來已經無法繼續讀取2個字節了, 是否就應該停止了?
實際過程中并未停止,而是進行了第三次讀取,只讀取了剩余1個字節,并頂替到了數組的0下標位置中。
接下來第4次讀取,才發現移到末尾,而后返回-1.停止讀取
所以此處存疑-----為什么當剩余只有1個字節,而要求是讀取2個字節時,還可以繼續讀取?
那么我們查看此方法源碼,發現其本質是調用的其它方法readBytes(b, 0, b.length);
public int read(byte b[]) throws IOException { return readBytes(b, 0, b.length); }
繼續查看readBytes(b, 0, b.length)方法是native方法代表該方法是有實現體的但不是在JAVA語言中實現的導致沒辦法看具體實現
但是可以理解參數b是我們設置的數組,0是int型,最后一個參數是數組的長度
private native int readBytes(byte b[], int off, int len) throws IOException;
那么我們查看FileInputStream的父類InputStream,發現有關于這個方法的實現,
我們現在考慮第三次讀取的時候方法執行情況,此時b是[51,52].off 是0,len是2。數據流中就只有一個字節存在了
if else if的這個條件判斷發現都不符合,繼續往下執行。
read()--該方法代表從流中讀取一個字節,而流中此時剛好還有一個字節存在,該方法執行沒有問題。返回值為53
繼續往下執行發現b[0]=(byte)53.也就是將讀取到的int型轉為字節并存儲在數組中的第一個位置,此時數組內容為[53,52]
繼續執行進入for循環,此時流中已沒有字節,那么read()方法返回未-1退出循環。返回變量i的值即是1.
也就是此次方法執行讀取了1個字節到數組中。且讀取到了文件的末尾,因此第4次執行的時候到int c=read()方法時就已經返回-1,并沒有替換數組中的值了
public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; }
讀取過程圖解:
4. 假設流中一共有5個字節,但是我們設定的字節數組長度為10,那么讀取幾次?每次情況是怎么樣的?
public class FileStream { public static void main(String[] args) { //建立文件對象 File file=new File("C:\\Users\\Administrator\\Desktop\\1.txt"); try { //建立鏈接 FileInputStream fileInputStream=new FileInputStream(file); int n=0; byte[] b=new byte[10]; int i=0; while (n!=-1) //當n不等于-1,則代表未到末尾 { n=fileInputStream.read(b);//返回實際讀取到字節數組中的字節數 System.out.println(n); System.out.println(Arrays.toString(b)); //讀取后的字節數組內容 i++; System.out.println("執行次數:"+i); } System.out.println(new String(b)); } catch (FileNotFoundException e) { System.out.println("文件不存在或者文件不可讀或者文件是目錄"); } catch (IOException e) { System.out.println("讀取過程存在異常"); } } }
執行結果如下:
結合上面提到的源碼我們可以發現,源碼中的for循環,盡管len是10(數組長度),但是當i=5時,流中的字節已經讀取完畢,指針移到文件的末尾,因此不會繼續執行for循環。并且返回5,剛好符合結果中第一次實際讀取5個字節到數組中。第二次讀取時指針已到末尾。因此int c = read()這里返回-1。就已經結束了方法,并沒有改變數組也沒有再次for循環
但是這種情況存在一個問題:即數組中有5個位置被浪費了,并沒有任何數據在里面
具體讀取圖解:
結合以上兩種情況,那么發現在使用read(byte b[])方法時的數組長度至關重要,若長度小于流的字節長度,那么最后得出的內容會出現丟失。若大于流的字節長度,那么最后數組的內存就浪費了,那么就需要根據文件的字節長度來設置數組的長度
byte[] b=new byte[(int) file.length()];
3.3)從輸入流中讀取最多len個字節到字節數組中(從數組的off位置開始存儲字節),當len為0時則返回0,如果len不為零,則該方法將阻塞,直到某些輸入可用為止--此處存疑
public int read(byte[] b,int off,int len) throws IOException
源碼如下
public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; }
3.4)關閉此輸入流并釋放與該流關聯的所有系統資源---即釋放與實際文件的連接(查看源碼可發現有同步鎖鎖住資源,因此關閉流釋放鎖)
public void close() throws IOException
1、查看三種read方法源碼,其本質都是利用for循環對內容進行單字節的讀取
2、從代碼形式看,使用read(byte[] b)較為直觀和簡便,因此項目中可以此方法為主進行數據讀取
到此,關于“java的FileInputStream流如何使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。