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