JavaSE——IO(上)(File、字节流、字符流、转换流、打印流、缓存流)
第3節 IO(上)
一、File類與文件基本操作
在程序中經常需要用到文件的操作,Java有專門的類來進行文件的操作——File類。
1.1 File類概述
它是對文件和目錄路徑名的抽象表示。 即它本身不是一個文件,只是一個抽象表示,一個用于操作文件的對象(實現后)。
用戶界面和操作系統使用依賴于系統的路徑名字符串來命名文件和目錄。此類提供了一個抽象的,與系統無關的分層路徑名視圖。
1.2 絕對路徑于相對路徑
-
絕對路徑 :從盤符開始,是一個完整的路徑,例如:c://a.txt;
-
相對路徑 :在Java代碼中是相對于項目目錄路徑 ,這是一個不完整的便捷路徑,在Java開發中很常用。
看一個例子就明白了:
package com.kaikeba.coreclasslibrary.io;import java.io.File;public class path {public static void main(String[] args) {File file1 = new File("c://a.txt");File file2 = new File("a.txt");System.out.println("file1的路徑:"+file1.getAbsolutePath());System.out.println("file2的路徑:"+file2.getAbsolutePath());} }結果如下: file1的路徑:c:\a.txt file2的路徑:E:\JAVAEE開發工程師\code\classcode\a.txt其中項目的路徑就是E:\JAVAEE開發工程師\code\classcode。
1.3 File類字段
這邊的路徑分隔符和默認名稱分隔符是為了適應不同的os,因為在不同的os上它們是不一樣的,為了避免經常修改這些,可以利用File類給出的這些字段,在不同的os上會給出相應的分隔符,下面看一下Windows上的分隔符是什么:
System.out.println(File.pathSeparator); System.out.println(File.separator);結果如下: ; \1.4 構造方法
parent和child構造的方法,parent是目錄,child是具體文件名。
1.5 方法
1、三個測試:
2、比較兩個抽象路徑名:
3、在該路徑下創建文件:存在則不新建
4、刪除文件:
5、判斷是否存在該文件:
6、得到絕對路徑:可以是File類或String字符串
7、得到文件或目錄名稱:
8、測試是否是絕對路徑、目錄、文件、隱藏文件:
9、返回文件的長度(大小):
10、列出該目錄下的所有文件或字符串路徑:
11、新建目錄或遞歸新建目錄
上述就是一些常用方法。
1.6 文件遍歷與文件過濾器
1.6.1 文件遍歷(充分利用File類的方法)
如何在一個路徑下找出所有的PDF文件?這就需要遍歷路徑下的所有文件和目錄,遇到目錄還要在進目錄繼續遍歷:
代碼如下:
package com.kaikeba.coreclasslibrary.io;import java.io.File;public class listfiles {public static void main(String[] args) {File e = new File("e:\\");File[] files = e.listFiles();listFiles(files);}private static void listFiles(File[] files) {if(files != null && files.length > 0) {for(File file:files) {if(file.isFile()) {//文件if(file.getName().endsWith(".pdf")) {//找到了一個大于10M的PDF文件if(file.length()>10*1024*1024) {System.out.println(file.getAbsolutePath());}}}else {//文件夾,繼續遞歸遍歷File[] files2 = file.listFiles();listFiles(files2);}}}} }結果就是遍歷的所有在E盤下的PDF的路徑...1.6.2 文件過濾器
上述遍歷的框架已經有了,但是在判斷是否是我們要找的文件時if判斷是我們自己寫的,還有一種方法,雖然不常用,但是也可以了解。
listFiles方法的參數里有一個FileFilter類型的filefilter變量:
FileFilter是一個接口,只有一個抽象方法:
可以把判斷條件寫在accept里面,如果返回true就保存該文件,返回false就不保留該文件,例子如下:
package com.kaikeba.coreclasslibrary.io;import java.io.File; import java.io.FileFilter;public class filefilter2 {public static void main(String[] args) {File e = new File("e:\\");listFiles(e);}private static void listFiles(File file) {//1. 創建一個過濾器規則 并 描述規則//2. 通過文件獲取子文件夾File[] files = file.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {if(pathname.getName().endsWith(".pdf") || pathname.isDirectory()) {return true;}return false;}});if(files != null || files.length > 0) {for (File f : files) {if (f.isDirectory()) {listFiles(f);} else {System.out.println(f.getAbsolutePath());}}}} }返回結果如上述代碼一致。二、流(輸入輸出)概述
計算機中的任何數據(文本,圖片,視頻,音樂等等)都是以二進制形式存儲的。在數據傳輸時,也都是以二進制形式存儲的。后續學習的任何流,在傳輸時底層都是二進制。
可以將數據傳輸的操作,看做一種數據的流動。按照流動的方向,分為輸入Input和輸出Output。
Java中的IO操作主要指的是java.io包下的一些常用類的使用,通過這些類,對數據進行讀取(輸入Input)和寫出(Output)。
IO流的分類:
-
按照流的方向來分,可以分為:輸入流和輸出流 ;
-
按照流動的數據類型來分,可以分為:字節流和字符流 。
字節流:
-
輸入流:InputStream
-
輸出流:OutputStream
字符流:
-
輸入流:Reader
-
輸出流:Writer
三、字節流
3.1 字節輸出流OutputStream類
3.1.1 OutputStream類概述
此抽象類是表示輸出字節流的所有類的超類,輸出流接收輸出字節并將它們發送到某個接收器。它的實現子類最常用的就是:FileOutputStream類。
方法:
1、關閉輸出流:
2、刷新緩存,強制寫出:
3、寫出操作:將字節數組或字節寫出
3.1.2 FileOutputStream類
是OutputStream類最常用的一個實現類。
構造方法:
指定要輸出寫入的文件對象或String路徑(文件不存在會自動創建),append表示是否追加寫入,true為追加模式,false為清空內容從頭寫入。
方法: 基本就是使用OutPutStream類的方法。
看個例子:
package com.kaikeba.coreclasslibrary.io;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class outputstream {public static void main(String[] args) throws IOException {//FileOutputStreamFileOutputStream fos = new FileOutputStream("a.txt"); // byte[] bytes = {65,66,67,68,69}; // fos.write(65);byte[] bytes = "ABCDEF".getBytes(); // fos.write(bytes);fos.write(bytes, 1, 2);fos.close();System.out.println("已經寫出");} }結果為: BC3.2 字節輸入流InputStream類
3.2.1 InputStream類概述
此抽象類是表示輸入字節流的所有類的超類。最常見的子類是FileInputStream類。
方法:
1、關閉輸入流:
2、讀取下一個字節:
3、讀取一些字節:
4、讀取一些字節,并指定開始位置和讀取個數:
注意: 讀取的方法返回的都是讀取到的有效字節的個數 ,如果已經到文件末尾,將會返回-1 。
5、其他一些讀取方法:
6、跳過并丟棄輸入流的n字節數據:
3.2.2 FileInputStream類
是InputStream類最常用的一個子類。
構造方法:
給定要讀取的文件。
方法:
看一個例子:
首先在a.txt文件中寫有Hello InputStream的內容。下面來將其文件中的內容讀取到程序中:
package com.kaikeba.coreclasslibrary.io;import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream;public class inputstream {public static void main(String[] args) throws IOException {//FileInputStreamInputStream fis = new FileInputStream("a.txt");while(true) {byte b = (byte)fis.read();//b如果為-1,表示已經讀取到文件末尾,讀取完畢if(b == -1) {break;}System.out.print((char)b);}} }結果為: Hello InputStream但是這種方式每次只讀取一個字節,需要很多次讀取(read)操作,與文件的連接次數太多會拖慢程序的速度,所以可以使用read的另一個方法:
package com.kaikeba.coreclasslibrary.io;import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream;public class inputstream {public static void main(String[] args) throws IOException {//FileInputStreamInputStream fis = new FileInputStream("a.txt");//推薦下面這種方式讀取,因為讀取的次數較少byte[] bytes = new byte[10];int len = fis.read(bytes);System.out.println(new String(bytes,0,len));len = fis.read(bytes);System.out.println(new String(bytes,0,len));len = fis.read(bytes);System.out.println(len);fis.close();} }結果如下: Hello Inpu tStream -1用一個字節數組來接收讀取到的固定長度的數據,但是要注意,讀到最后,如果不滿10個字節了,那么返回的將不是希望的結果,因為是將新讀取到的覆蓋數組,未滿10個最后幾個后面將不會被覆蓋,即多出幾個沒用的字節。
解決:按照上述的寫法,將成功讀取到的字節個數接收,并用String的bytes數組指定長度的構造方法來輸出。
優點:這樣大大減少了連接文件的次數,加速了程序的運行。
3.2.3 字節流讀取文字
如果將上述a.txt中的內容換成中文,比如 鋤禾日當午,汗滴禾下土 ,再來看上述代碼的輸出:
鋤禾日� ��午,� �滴禾下這并不是亂碼,因為中文編碼一般不是一個字節來表示一個字,所以它10個字節可能讀到的是3個半字,那半個字是無法恢復的,它比亂碼更加可怕 ,這就是字節流的缺點所在,后續學習字符流就是專門解決讀取文字的問題。
四、字符流
字符流與字節流的區別就是字節流是一個字節一個字節的傳輸,但是字符流不太一樣,雖然內部還是傳輸的字節,但是因為一個字符,比如一些非英文文字,需要幾個字節來表示一個字符,所以它會一次讀或寫一個字符,這樣就可以避免3.2.3出現的問題。
4.1 字符輸出流Writer類
4.1.1 Writer類概述
用于寫入字符流的抽象類。最常用的子類為OutputStreamWriter下的FileWriter。其中OutputStreamWriter后續介紹。
方法:
比較常用的有:
1、append:將字符或序列追加到此Writer,注意它的返回類型為Writer,即追加完后的文件自己。
其實它內部調用的還是write方法,但是write方法沒有返回,這就使得append方法可以連續操作(當然用write也可以達到一樣的效果)。
2、close:關閉流,關閉之前先刷新緩存
3、flush:刷新緩存,如果不刷新,內容是寫在緩存區的,還沒有真正寫入文件:
close方法中已經調用了flush,這里我們不使用close,只看使用flush和不使用flush的區別:
目前b.txt是空的,下面調用:
public class flush {public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("b.txt", true);fw.append("鋤禾日當午").append(",").append("汗滴禾下土");} }結果還是空的,因為沒有刷新緩沖區:
如果加上flush:
FileWriter fw = new FileWriter("b.txt", true); fw.append("鋤禾日當午").append(",").append("汗滴禾下土"); fw.flush();結果為:
4、write:寫一個字符數組,字符數組的一部分,一個字符,一個字符串,字符串的一部分:
4.1.2 FileWriter類
使用默認緩沖區大小將文本寫入字符文件。構造方法:
參數:
1、File file / String fileName:要將內容寫入的文件;
2、Charset charset:指定編碼集,常見的有"gbk"、“uft8”;
3、boolean append:是否是追加模式寫入;
方法沒有新的,都是用的或重寫的父類方法。
看個例子:
package com.kaikeba.coreclasslibrary.io;import java.io.FileWriter; import java.io.IOException; import java.io.Writer;public class writer {public static void main(String[] args) throws IOException {//Writer//FileWriterFileWriter fw = new FileWriter("b.txt");fw.write('a');fw.write("鋤禾日當午");//注意append的用法,因為它返回文件本身fw.append(",").append("汗滴禾下土");fw.close();} }b.txt中的內容為: a鋤禾日當午,汗滴禾下土4.2 字符輸入流Reader類
4.2.1 Reader類概述
用于讀取字符流的抽象類。常用的子類為InputStreamReader下的FileReader類。
方法:
常用的有:
1、close:關閉流
2、read:讀入一個字符,返回的就是它的int型編碼
3、將字符讀入數組(一部分)或指定緩沖區
4.2.2 FileReader類
使用默認緩沖區大小從字符文件中讀取文本,使用指定的編碼集或默認編碼集。
構造方法:
參數:
1、File file / String fileName:從哪個文件讀取;
2、Charset charset:指定編碼集。
方法也沒有新的。
看個例子:
package com.kaikeba.coreclasslibrary.io;import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException;public class reader {public static void main(String[] args) throws IOException {//ReaderFileReader fr = new FileReader("b.txt");/*while(true) {int c = fr.read();if(c == -1) {break;}System.out.print((char)c);}*/System.out.println("a:"+fr.read());System.out.println("鋤:"+fr.read());char[] chars = new char[100];int len = fr.read(chars);System.out.println(new String(chars, 0, len));fr.close();} }結果如下: a:97 鋤:38148 禾日當午,汗滴禾下土五、字節流轉換字符流
5.1 InputStreamReader類
InputStreamReader類是從字節流到字符流的橋接器,這也是比較常用的,比如從外界接收到的流一般都是字節流,如果要正確讀取文字的話,需要轉為字符流。每次調用read方法都可能導致從底層字節輸入流中讀取一個或者多個字節。
它是Reader類的一個子類,是FileReader的父類。
構造方法:
主要的參數是要傳入一個字節輸入流InputStream。
方法:
主要是read方法,可以讀取一個字符或者將字符輸入數組的一部分。
看一個例子:
public class zhuanhuanliu {public static void main(String[] args) throws IOException {//字節流 ‘裝飾’為 字符流 :使用了裝飾者設計模式//自己新建一個字節輸入流,用于模仿外界接收到的FileInputStream fis = new FileInputStream("b.txt");//將字節輸入流,轉換為字符輸入流//參數1:要轉換的字節流//參數2:指定編碼名稱InputStreamReader isr = new InputStreamReader(fis,"utf8");while(true) {int c = isr.read();if(c == -1) {break;}System.out.print((char)c);}} }結果就是將b.txt中的內容全部輸出5.2 OutputStreamWriter類
OutputStreamWriter是從字符流到字節流的橋接器,使用指定的charset將寫入其中的字符編碼為字節。調用write方法都會導致在給定字符上調用編碼轉換器,生成的字節在寫入底層輸出流之前在緩沖區中累積。
它是Writer類的子類,是FileWriter類的父類。
構造方法:
主要參數是要轉換的輸出字節流。
方法:
寫一個字符或字符串或字符數組的一部分。
看一個例子:
public class zhuanhuanliu2 {public static void main(String[] args) throws IOException {//轉換流//字符流 ‘裝飾’為 字節流 :使用了裝飾者設計模式FileOutputStream fos = new FileOutputStream("b.txt");OutputStreamWriter osw = new OutputStreamWriter(fos);osw.write("床前明月光");osw.close();} }即將“床前明月光”寫入b.txt。六、打印流與緩存流
6.1 PrintStream類
PrintStream類向另一個輸出流添加功能,即能夠方便地打印各種數據值的表示。
構造方法:
傳入的參數主要是要寫入的文件,可以是File型,String型或者字節輸出流。
方法:
1、追加:
2、關閉、刷新:
3、打印
4、打印并換行:
5、寫入:
看個例子:
public class print_bufferedreader {public static void main(String[] args) throws IOException {//(字符輸出)打印流,注意它會自動刷新PrintStream ps = new PrintStream("b.txt");ps.println("鋤禾日當午1");ps.println("鋤禾日當午2");ps.println("鋤禾日當午3");} }b.txt中的內容就是: 鋤禾日當午1 鋤禾日當午2 鋤禾日當午36.2 PrintWriter類
它和PrintStream類基本上差不多,主要的區別是寫入的時候不會自動刷新。
public class print_bufferedreader {public static void main(String[] args) throws IOException {PrintWriter pw = new PrintWriter("b.txt");pw.println("鋤禾日當午1");pw.println("鋤禾日當午2");pw.println("鋤禾日當午3");pw.flush();} }b.txt中的內容就是: 鋤禾日當午1 鋤禾日當午2 鋤禾日當午3也可以用輸出流作為參數:
public class print_bufferedreader {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("b.txt");PrintWriter pw = new PrintWriter(fos);pw.println("勇敢牛牛");pw.close();} }b.txt中的內容就是: 勇敢牛牛6.3 BufferedReader類
從字符輸入流中讀取文本,緩沖字符,以便有效地讀取字符,數組和行。可以指定緩沖區大小,或者可以使用默認大小。
構造方法:
方法:
它比較獨特的一個方法是readLine方法:讀取一行文字,看一個例子:
public class print_bufferedreader {public static void main(String[] args) throws IOException {//緩存讀取流,將字符輸入流 轉換為帶有緩存 可以一次讀取一行的緩存字符讀取流FileReader fw = new FileReader("b.txt");BufferedReader br = new BufferedReader(fw);String text = br.readLine();System.out.println(text);} }結果解釋讀取b.txt中的一行文字。七、收集異常日志
在程序運行過程中,不可能一直看著屏幕上的輸出,所以當出現異常的時候,利用IO我們可以將這些異常寫到指定的文件中,后續有時間打開這個記錄異常的文件查看即可。
看一個例子:
public class printstacktrace {public static void main(String[] args) throws FileNotFoundException {try{//將可能出現異常的內容用try捕捉String s = null;s.toString();}catch (Exception e) {//新建打印流,指定輸出的文件PrintWriter pw = new PrintWriter("b.txt");//把時間也記錄下來SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");pw.println(sdf.format(new Date()));//將異常輸出到打印流中e.printStackTrace(pw);//關閉打印流pw.close();}} }b.txt中的內容就是異常: 2021-09-13 19:57 java.lang.NullPointerExceptionat com.kaikeba.coreclasslibrary.io.printstacktrace.main(printstacktrace.java:12)總結
以上是生活随笔為你收集整理的JavaSE——IO(上)(File、字节流、字符流、转换流、打印流、缓存流)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TypeError: 'numpy.in
- 下一篇: np.squeeze()