java IO之 File类+字节流 (输入输出 缓冲流 异常处理)
1. File類
File 路徑問題:
上下級文件夾之間使用分隔符分開:
在Windows中分隔符為‘\’ ,在Unix/Linux中分隔符為‘/’
跨平臺分隔符:
專業的做法是使用File.separatorChar,這個值會根據系統得到的相應的分隔符。
例:new File("c:"+File.separatorChar+"a.txt");
注意,如果是使用“\” ,則需要進行轉義,寫為“\\”才可以
? ? 絕對路徑與相對路徑:
對于UNIX平臺,絕對路徑名的前綴是"/"。相對路徑名沒有前綴。
對于Windows平臺,絕對路徑名的前綴由驅動器號和一個":"組成,例"c:\\..."。相對路徑沒有盤符前綴。
相對路徑:
??? 相對路徑是指相對于某位置的路徑,是指相對于當前目錄。
??? 在執行Java程序時,相對路徑為執行java命令時當前所在的目錄。
File 常用方法:
????
創建:
| ??? createNewFile()?? 在指定位置創建一個空文件,成功就返回true,如果已存在就不創建然后返回false ?????? mkdir()?????????? 在指定位置創建目錄,這只會創建最后一級目錄,如果上級目錄不存在就拋異常。 ?????? mkdirs()????? 在指定位置創建目錄,這會創建路徑中所有不存在的目錄。 ?????? renameTo(File dest)? 重命名文件或文件夾,也可以操作非空的文件夾,文件不同時相當于文件的剪切,剪切時候不能操作非空的文件夾。移動/重命名成功則返回true,失敗則返回false。 |
刪除:
| delete()????? 刪除文件或一個空文件夾,如果是文件夾且不為空,則不能刪除,成功返回true,失敗返回false。 deleteOnExit()??? 在虛擬機終止時,請求刪除此抽象路徑名表示的文件或目錄,保證程序異常時創建的臨時文件也可以被刪除 |
判斷:
| exists()????? 文件或文件夾是否存在。 isFile()????? 是否是一個文件,如果不存在,則始終為false。 isDirectory() 是否是一個目錄,如果不存在,則始終為false。 isHidden()??? 是否是一個隱藏的文件或是否是隱藏的目錄。 isAbsolute()? 測試此抽象路徑名是否為絕對路徑名。 |
獲取:
| getName()???? 獲取文件或文件夾的名稱,不包含上級路徑。 getPath()?????? 返回絕對路徑,可以是相對路徑,但是目錄要指定 getAbsolutePath() 獲取文件的絕對路徑,與文件是否存在沒關系 length()????? 獲取文件的大小(字節數),如果文件不存在則返回0L,如果是文件夾也返回0L。 getParent()?????? 返回此抽象路徑名父目錄的路徑名字符串;如果此路徑名沒有指定父目錄,則返回null。 lastModified()??? 獲取最后一次被修改的時間。 ?文件夾相關: staic File[] listRoots() ? ? ? 列出所有的根目錄(Window中就是所有系統的盤符) list()??????????????????????????? 返回目錄下的文件或者目錄名,包含隱藏文件。對于文件這樣操作會返回null。 list(FilenameFilter filter) 返回指定當前目錄中符合過濾條件的子文件或子目錄。對于文件這樣操作會返回null。 listFiles()???????????????? 返回目錄下的文件或者目錄對象(File類實例),包含隱藏文件。對于文件這樣操作會返回null。 listFiles(FilenameFilter filter)?? 返回指定當前目錄中符合過濾條件的子文件或子目錄。對于文件這樣操作會返回null。 |
2. 字節流
什么事字節流:
計算機都是二進制數據,一個字節是8個2進制位。字節可以表示所有的數據,比如文
本,音頻,視頻,圖片,都是作為字節存在的。也就是說字節流處理的數據非常多。
在文本文件中存儲的數據是以我們能讀懂的方式表示的。而在二進制文件中存儲的數據
是用二進制形式表示的。我們是讀不懂二進制文件的,因為二進制文件是為了讓程序來讀取
而設計的。例如:Java的源程序(.java源文件)存儲在文件文本中,可以使用文本編輯器
閱讀,但是Java的類(字節碼文件)存儲在二進制文件中,可以被Java虛擬機閱讀。二進
制文件的優勢在于它的處理效率比文本文件高。
我們已經知道File對象封裝的是文件或者路徑屬性,但是不包含向(從)文件讀(寫)
數據的方法。為了實現對文件的讀和寫操作需要學會正確的使用Java的IO創建對象。
字節流的抽象基類:
輸入流:java.io.InputStream
輸入流:java.io.OutputStream
特點:
字節流的抽象基類派生出來的子類名稱都是以其父類名作為子類名的后綴。
如:FileInputStream,ByteArrayInputStream
說明:
字節流處理的單元是一個字節:用于操作二進制文件(計算機中所有文件都是二進制文件)
輸入流讀取方式1:
read方法()
一次讀取一個字節,讀到文件末尾返回-1.
仔細查看api文檔發現read方法如果讀到文件的末尾會返回-1。那么就可以通過read方法的返回值是否是-1來控制我們的循環讀取。
private static void showContent(String path) throws IOException {// 打開流FileInputStream fis = new FileInputStream(path);int len = fis.read();while (len != -1) {System.out.print((char)len);len = fis.read();}// 使用完關閉流 fis.close();}?
寫成:
private static void showContent(String path) throws IOException {// 打開流FileInputStream fis = new FileInputStream(path);int len;while ((len = fis.read()) != -1) {System.out.print((char) len);}// 使用完關閉流 fis.close();}?
輸入流讀取方式2:
使用read(byte[] b)?方法。使用緩沖區(關鍵是緩沖區大小的確定)
使用read方法的時候,流需要讀一次就處理一次,可以將讀到的數據裝入到字節數組中,一次性的操作數組,可以提高效率。
private static void showContent2(String path) throws IOException {// 打開流FileInputStream fis = new FileInputStream(path);// 通過流讀取內容byte[] byt = new byte[5];int len = fis.read(byt);for (int i = 0; i < byt.length; i++) {System.out.print((char) byt[i]);}// 使用完關閉流 fis.close();}?
問題1:緩沖區大小
那么字節數組如何定義?定義多大?
可以嘗試初始化長度為5的byte數組。通過read方法,往byte數組中存內容
那么該read方法返回的是往數組中存了多少字節。
數據讀取不完.
測試發現問題,由于數組太小,只裝了5個字節。而文本的字節大于數組的長度。那么很顯然可以將數組的長度定義大一些。例如1024個。
?緩沖區有默認值.
測試,打印的效果打印出了很多0,因為數組數組有默認初始化值,所以,我們將數組的數據全部都遍歷和出來.現在需要的是取出數組中的部分數據.需要將循環條件修改仔細查看api文檔。發現該方法read(byte[] b)返回的是往數組中存入了多少個字節。就是數組實際存儲的數據個數。
private static void showContent2(String path) throws IOException {// 打開流FileInputStream fis = new FileInputStream(path);// 通過流讀取內容byte[] byt = new byte[1024];int len = fis.read(byt);for (int i = 0; i <len; i++) {System.out.print(byt[i]);} // 使用完關閉流 fis.close();}?
?
總結:
?
問題一:為什么打印的不是字母而是數字,
?
????????是字母對應的碼值。
?
????????如何顯示字符,強轉為char即可
?
問題二:注意:回車和換行的問題。
?
????????windows的換車和換行是"\r\n"?對應碼表是13和10?。
?
?
輸入流讀取方式3:
使用read(byte[] b,int off,int len)查看api文檔,
b顯然是一個byte類型數組,當做容器來使用
?
off,是指定從數組的什么位置開始存字節
?
len,希望讀多少個
其實就是把數組的一部分當做流的容器來使用。告訴容器,從什么地方開始裝要裝多少。
?
private static void showContent3(String path) throws IOException {// 打開流FileInputStream fis = new FileInputStream(path);// 通過流讀取內容byte[] byt = new byte[1024];// 從什么地方開始存讀到的數據int start = 5;// 希望最多讀多少個(如果是流的末尾,流中沒有足夠數據)int maxLen = 6;// 實際存放了多少個int len = fis.read(byt, start, maxLen);for (int i = start; i < start + maxLen; i++) {System.out.print((char) byt[i]);}// 使用完關閉流 fis.close();}?
測試skip方法
通過Io流,讀取"c:/a.txt"文件中的第9個字節到最后所有的內容并在控制臺顯示出來。
分析:其實就是要跳過文件中的一部分字節,需要查找API文檔。可以使用skip方法skip(long n),參數跟的是要跳過的字節數。
我們要從第9個開始讀,那么要跳過前8個即可。
private static void showContent4(String path) throws IOException {// 打開流FileInputStream fis = new FileInputStream(path);// 通過流讀取內容byte[] byt = new byte[1024];fis.skip(8);int len = fis.read(byt);System.out.println(len);System.out.println("**********");for (int i = 0; i < len; i++) {System.out.println((char) byt[i]);}// 使用完關閉流 fis.close(); }?
輸入流讀取方式4:
使用緩沖(提高效率),并循環讀取(讀完所有內容).
總結:讀完文件的所有內容。很顯然可以使用普通的read方法,一次讀一個字節直到讀到文件末尾。為了提高效率可以使用read(byte[] byt);方法就是所謂的使用緩沖提高效率。我們可以讀取大文本數據測試(大于1K的文本文件.)
private static void showContent5(String path) throws IOException {FileInputStream fis = new FileInputStream(path);byte[] byt = new byte[1024];int len = fis.read(byt);System.out.println(len);String buffer = new String(byt, 0, len);System.out.print(buffer);}?
????注意:如何將字節數組轉成字符串?可以通過創建字符串對象即可。
發現:一旦數據超過1024個字節,數組就存儲不下。
如何將文件的剩余內容讀完?
我們可以通過通過循環保證文件讀取完。
private static void showContent7(String path) throws IOException {FileInputStream fis = new FileInputStream(path);byte[] byt = new byte[1024];int len = 0;while ((len = fis.read(byt)) != -1) {System.out.println(new String(byt, 0, len));}}?
輸出流寫出方式1:
使用write(int b)方法,一次寫出一個字節.
在C盤下創建a.txt文本文件
public class IoTest2 {public static void main(String[] args) throws IOException {String path = "c:\\a.txt";writeTxtFile(path);}private static void writeTxtFile(String path) throws IOException {// 1:打開文件輸出流,流的目的地是指定的文件FileOutputStream fos = new FileOutputStream(path);// 2:通過流向文件寫數據fos.write('j');fos.write('a');fos.write('v');fos.write('a');// 3:用完流后關閉流 fos.close();} }?
注意:使用write(int b)方法,雖然接收的是int類型參數,但是write?的常規協定是:向輸出流寫入一個字節。要寫入的字節是參數?b?的八個低位。b?的?24?個高位將被忽略。
?
?
輸出流寫出方式2:
使用write(byte[] b),就是使用緩沖.提高效率.
?
上述案例中的使用了OutputStram?的write方法,一次只能寫一個字節。成功的向文件中寫入了內容。但是并不高效,如和提高效率呢?是否應該使用緩沖,根據字節輸入流的緩沖原理,是否可以將數據保存中字節數組中。通過操作字節數組來提高效率。查找API文檔,在OutputStram類中找到了write(byte[] b)方法,將?b.length?個字節從指定的byte?數組寫入此輸出流中。
如何將字節數據保存在字節數組中,以字符串為例,”hello , world”?如何轉為字節數組。顯然通過字符串的getBytes方法即可。
?
public class IoTest2 {public static void main(String[] args) throws IOException {String path = "c:\\a.txt";writeTxtFile(path);}private static void writeTxtFile(String path) throws IOException {// 1:打開文件輸出流,流的目的地是指定的文件FileOutputStream fos = new FileOutputStream(path);// 2:通過流向文件寫數據byte[] byt = "java".getBytes();fos.write(byt);// 3:用完流后關閉流 fos.close();} }?
仔細查看a.txt文本文件發現上述程序每運行一次,老的內容就會被覆蓋掉。,那么如何不覆蓋已有信息,能夠往a.txt里追加信息呢。查看API文檔,發現FileOutputStream類中的構造方法中有一個構造可以實現追加的功能FileOutputStream(File file, boolean append)??第二個參數,append -?如果為?true,則將字節寫入文件末尾處,而不是寫入文件開始處
private static void writeTxtFile(String path) throws IOException {// 1:打開文件輸出流,流的目的地是指定的文件FileOutputStream fos = new FileOutputStream(path,true);// 2:通過流向文件寫數據byte[] byt = "java".getBytes();fos.write(byt);// 3:用完流后關閉流 fos.close();}?
字節流文件拷貝
字節輸入輸出流綜合使用
?
通過字節輸出流向文件中寫入一些信息,并使用字節輸入流把文件中的信息顯示到控制臺上。
?
?
public class IoTest3 {public static void main(String[] args) throws IOException {String path = "c:\\b.txt";String content = "hello java";writeFile(path, content);readFile(path);}public static void writeFile(String path, String content)throws IOException {// 打開文件輸出流FileOutputStream fos = new FileOutputStream(path);byte[] buffer = content.getBytes();// 向文件中寫入內容 fos.write(buffer);// 關閉流 fos.close();}public static void readFile(String path) throws IOException {FileInputStream fis = new FileInputStream(path);byte[] byt = new byte[1024];int len = 0;while ((len = fis.read(byt)) != -1) {System.out.println(new String(byt, 0, len));}// 關閉流 fos.close();} }?
注意輸出流的細節:
????這個輸出流顯然只適合小數據的寫入,如果有大數據想要寫入,我們的byte數組,該如何定義?
?
上述案例中我們將輸入流和輸出流進行和綜合使用,如果嘗試進輸出流換成文本文件就可以實現文件的拷貝了.
什么是文件拷貝?很顯然,先開一個輸入流,將文件加載到流中,再開一個輸出流,將流中數據寫到文件中。就實現了文件的拷貝。
?
???字節流拷貝文件實現1
讀一個字節寫一個字節read?和write
?
?
?
?
?
?
???字節流拷貝文件實現2
使用字節數組作為緩沖區
?
問題1:?使用緩沖(字節數組)拷貝數據,拷貝后的文件大于源文件.
測試該方法,拷貝文本文件,仔細觀察發現和源文件不太一致。
打開文件發現拷貝后的文件和拷貝前的源文件不同,拷貝后的文件要比源文件多一些內容問題就在于我們使用的容器,這個容器我們是重復使用的,新的數據會覆蓋掉老的數據,顯然最后一次讀文件的時候,容器并沒有裝滿,出現了新老數據并存的情況。
所以最后一次把容器中數據寫入到文件中就出現了問題。
如何避免?使用FileOutputStream?的write(byte[] b, int off, int len)
b?是容器,off是從數組的什么位置開始,len是獲取的個數,容器用了多少就寫出多少。
?
public static void copyFile2(String srcPath, String destPath)throws IOException {// 打開輸入流,輸出流FileInputStream fis = new FileInputStream(srcPath);FileOutputStream fos = new FileOutputStream(destPath);// 讀取和寫入信息int len = 0;// 使用字節數組,當做緩沖區byte[] byt = new byte[1024];while ((len = fis.read(byt)) != -1) {fos.write(byt, 0, len);}// 關閉流 fis.close();fos.close();}?
使用緩沖拷貝視頻,可以根據拷貝的需求調整數組的大小,一般是1024的整數倍。發現使緩沖后效率大大提高。
字節流的異常處理
上述案例中所有的異常都只是進行了拋出處理,這樣是不合理的。所以上述代碼并不完善,因為異常沒有處理。
當我們打開流,讀和寫,關閉流的時候都會出現異常,異常出現后,后面的代碼都不會執行了。假設打開和關閉流出現了異常,那么顯然close方法就不會再執行。那么會對程序有什么影響?
public class IoTest4 {public static void main(String[] args) throws IOException,InterruptedException {String path = "c:\\b.txt";readFile(path);}private static void readFile(String path) throws IOException,InterruptedException {FileInputStream fis = new FileInputStream(path);byte[] byt = new byte[1024];int len = fis.read(byt);System.out.println(new String(byt, 0, len));// 讓程序睡眠,無法執行到close方法。Thread.sleep(1000 * 10);fis.close();} }?
?
?
在執行該程序的同時我們嘗試去刪除b.txt文件。如果在該程序沒有睡醒的話,我們是無法刪除b.txt?文件的。因為b.txt還被該程序占用著,這是很嚴重的問題,所以一定要關閉流。
目前我們是拋出處理,一旦出現了異常,close就沒有執行,也就沒有釋放資源。那么為了保證close的執行該如何處理呢。
?
那么就需要使用try{} catch(){}finally{}語句。try中放入可能出現異常的語句,catch是捕獲異常對象,fianlly是一定要執行的代碼
public class IoTest4 {public static void main(String[] args) throws IOException,InterruptedException {String path = "c:\\b.txt";readFile(path);}private static void readFile(String path) {FileInputStream fis = null;try {fis = new FileInputStream(path);byte[] byt = new byte[1024];int len = fis.read(byt);System.out.println(new String(byt, 0, len));} catch (IOException e) {// 拋出運行時異常throw new RuntimeException(e);} finally {// 把close方法放入finally中保證一定會執行// 先判斷是否空指針if (fis != null) {try {fis.close();} catch (Exception e) {throw new RuntimeException(e);}}}} }?
文件拷貝的異常處理:
public static void copyFile(String srcPath, String destPath) {FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream(srcPath);fos = new FileOutputStream(destPath);byte[] byt = new byte[1024 * 1024];int len = 0;while ((len = fis.read(byt)) != -1) {fos.write(byt, 0, len);}} catch (IOException e) {throw new RuntimeException(e);} finally {if (fis != null) {try {fis.close();} catch (IOException e) {throw new RuntimeException(e);}}if (fos != null) {try {fos.close();} catch (IOException e) {throw new RuntimeException(e);}}}}?
注意:
在最后的close代碼中可能會有問題,兩個close,如果第一個close方法出現了異常,并拋出了運行時異常,那么程序還是停止了。下面的close方法就沒有執行到。
那么為了保證close的執行,將第二個放到fianlly中即可。
?
public static void copyFile(String srcPath, String destPath) {FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream(srcPath);fos = new FileOutputStream(destPath);byte[] byt = new byte[1024 * 1024];int len = 0;while ((len = fis.read(byt)) != -1) {fos.write(byt, 0, len);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {if (fis != null) {fis.close();}} catch (IOException e) {throw new RuntimeException(e);} finally {if (fos != null) {try {fos.close();} catch (IOException e) {throw new RuntimeException(e);}}}}}?
字節緩沖流
?
緩沖流
上述程序中我們為了提高流的使用效率,自定義了字節數組,作為緩沖區.Java其實提供了專門的字節流緩沖來提高效率.
BufferedInputStream和BufferedOutputStream
BufferedOutputStream和BufferedOutputStream類可以通過減少讀寫次數來提高輸入和輸出的速度。它們內部有一個緩沖區,用來提高處理效率。查看API文檔,發現可以指定緩沖區的大小。其實內部也是封裝了字節數組。沒有指定緩沖區大小,默認的字節是8192。
顯然緩沖區輸入流和緩沖區輸出流要配合使用。首先緩沖區輸入流會將讀取到的數據讀入緩沖區,當緩沖區滿時,或者調用flush方法,緩沖輸出流會將數據寫出。
注意:當然使用緩沖流來進行提高效率時,對于小文件可能看不到性能的提升。但是文件稍微大一些的話,就可以看到實質的性能提升了。
?
public class IoTest5 {public static void main(String[] args) throws IOException {String srcPath = "c:\\a.mp3";String destPath = "d:\\copy.mp3";copyFile(srcPath, destPath);}public static void copyFile(String srcPath, String destPath)throws IOException {// 打開輸入流,輸出流FileInputStream fis = new FileInputStream(srcPath);FileOutputStream fos = new FileOutputStream(destPath);// 使用緩沖流BufferedInputStream bis = new BufferedInputStream(fis);BufferedOutputStream bos = new BufferedOutputStream(fos);// 讀取和寫入信息int len = 0;while ((len = bis.read()) != -1) {bos.write(len);}// 關閉流 bis.close();bos.close(); }}總結
以上是生活随笔為你收集整理的java IO之 File类+字节流 (输入输出 缓冲流 异常处理)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android相关使用工具
- 下一篇: 领航商务之选——金立M5 plus体验札