Java基礎(chǔ)之文件操作(IO流)
特意寫一章關(guān)于IO流的知識(shí),不為別的,是因?yàn)镮O流實(shí)在太重要了
文件
File?就是文件對(duì)象,我們電腦上的文件和文件夾都可以用這個(gè)File實(shí)例化
public?class?Test{ ????public?static?void?main(String[]?args){ ????????//?獲取絕對(duì)路徑D盤的hello文件夾 ????????File?f1?=?new?File("D:/hello"); ????????//?獲取相對(duì)路徑的hello.txt文件 ????????File?f2?=?new?File("hello.txt"); ????????//?獲取D盤的hello文件夾下hello.txt文件的實(shí)例 ????????File?f3?=?new?File(f1,"hello.txt"); ???????? ????????//?輸出三個(gè)文件或者文件夾的絕對(duì)路徑 ????????System.out.println(f1.getAbsolutePath()); ????????System.out.println(f2.getAbsolutePath()); ????????System.out.println(f3.getAbsolutePath()); ????}}123456789101112131415
上面代碼注釋講的已經(jīng)非常的詳細(xì)了,用三種方式創(chuàng)建一個(gè)文件對(duì)象,怎么獲取文件的絕對(duì)路徑
假設(shè)我們已經(jīng)實(shí)例化了一個(gè)File對(duì)象f
判斷是否存在?f.exists()
判斷是否是文件夾?f.isDirectory()
判斷是否是文件?f.isFile()
獲取文件的長度?f.length()
文件最后修改的時(shí)間?f.lastModified()
設(shè)置文件最后修改時(shí)間?f.setLastModified(0)?這里的0代表的是時(shí)間戳 也就是1970.1.1 08:00:00
文件重命名?f.renameTo(“newName”)
以字符串?dāng)?shù)組的形式,返回當(dāng)前文件夾下面的所有文件?f.list()
以文件數(shù)組的形式,返回當(dāng)前文件夾下面的所有文件?f.listFiles()
以字符串形式返回所在文件夾?f.getParent()
以字符串形式返回獲取所在文件夾?f.getParentFile()
創(chuàng)建一個(gè)文件夾?f.mkdir()?如果說f所在的父文件夾不存在就會(huì)拋出異常
創(chuàng)建一個(gè)文件夾?f.mkdirs()?如果說f所在的父文件夾不存在就會(huì)自動(dòng)給你創(chuàng)建一個(gè)父文件夾
刪除文件?f.delete()
JVM結(jié)束的時(shí)候刪除文件?f.deleteOnExit()
public?class?Test{ ????public?static?void?main(StringP[]?args){ ????????File?f?=?new?File("C:/WINDOWS"); ????????File[]?files; ????????int?k=0; ????????long?max?=?0; ????????if(f.exists){ ????????????//?把文件夾下面的所有文件都取出來 ????????????files?=?f.listFiles(); ????????????//?遍歷所有的文件取出體積最大的文件 ????????????for(int?i=0;i
編碼
編碼是信息從一種形式或格式轉(zhuǎn)換為另一種形式的過程
常見的編碼方式有如下幾種:
ISO-8859-1 ASCII?數(shù)字和西歐字母
GBK GB2312 BIG5?中文
UNICODE?(統(tǒng)一碼,萬國碼)
看樣子,我們的中文就是屬于這個(gè)GBK這種編碼了,也就是說中文只能用GBK編碼來存儲(chǔ)嘛?
這個(gè)肯定是錯(cuò)的,UNICODE稱為萬國碼,也就是全世界任何國家的字符都是可以儲(chǔ)存的,只不過,他占用的空間是最大的,比入英文字母只需要1字節(jié)的空間,漢字需要3字節(jié)的空間,但是Unicode它不管你是英文字母還是漢字,都統(tǒng)一給你4個(gè)字節(jié),這樣的話是比較浪費(fèi)空間的,所以就誕生了UTF-8這種基于Unicode減肥版本的編碼方式。
UTF-8它可以對(duì)英文或者數(shù)字使用一個(gè)字節(jié),對(duì)漢字使用三個(gè)字節(jié),這樣的話就避免了空間的浪費(fèi)。
Java源代碼中的漢字在執(zhí)行之后,都會(huì)變成JVM中的字符,而這些中文字符采用的編碼方式,都是Unicode
流
什么流?流就是一系列的數(shù)據(jù)。
當(dāng)不同的介質(zhì)之間有數(shù)據(jù)交互的時(shí)候,Java就是使用流來實(shí)現(xiàn)
比如讀取文件的數(shù)據(jù)到程序中,站在程序的角度來看,就叫做輸入流。
如何創(chuàng)建文件輸入流,看以下代碼:
public?class?Test{ ????public?static?void?main(String[]?args){ ????????try{ ????????????File?f?=?new?File("D:/hello.txt"); ????????????//?通過這個(gè)文件輸入流可以將硬盤上文件中的數(shù)據(jù)讀取到j(luò)ava程序內(nèi)存中來 ????????????FileInputStream?fis?=?new?FileInputStream(f); ????????}catch(IOException?e){ ????????????e.printStackTrace(); ????????} ????}}1234567891011
InputStream是字節(jié)輸入流,同時(shí)也是抽象類,只提供方法聲明,不提供方法的具體實(shí)現(xiàn)。
FileInputStream是InputStream的子類,我們下面就用FileInputStream來實(shí)現(xiàn)讀取文件的內(nèi)容
public?class?Test{ ????public?static?void?main(String[]?args){ ????????try{ ????????????//?準(zhǔn)備一個(gè)文本文件,里面內(nèi)容是AB ????????????File?f?=?new?File("D:/test.txt"); ????????????//?創(chuàng)建文件輸入流 ????????????FileInputStream?fis?=?new?FileInputStream(f); ????????????//?創(chuàng)建一個(gè)字節(jié)數(shù)組,它的長度就是文件的長度 ????????????byte[]?all?=?new?byte[(int)f.length()]; ????????????//?以字節(jié)流的形式讀取文件中的所有內(nèi)容到字節(jié)數(shù)組 ????????????fis.read(all); ????????????for(byte?b?:?all){ ????????????????System.out.println(b); ???????????} ????????????fis.close(); ???????????? ????????}catch(IOException?e){ ????????????e.printStackTrace(); ????????} ????}}123456789101112131415161718192021
結(jié)果是65和66 也就是A和B對(duì)應(yīng)的ASCII碼
OutputStream 是字節(jié)輸出流,更InputStream也是一樣的,抽象類。
所以我們用FileOutputStream為例往文件中寫入數(shù)據(jù)
public?class?Test{ ????public?static?void?main(String[]?args){ ????????try{ ????????????//?準(zhǔn)備一個(gè)文本文件,里面內(nèi)容是空的 ????????????File?f?=?new?File("D:/test.txt"); ????????????//?創(chuàng)建文件輸出流 ????????????FileOutputStream?fis?=?new?FileOutputStream(f); ????????????//?創(chuàng)建一個(gè)字節(jié)數(shù)組,里面寫上A和B的ASCII碼 ????????????byte[]?data?=?{65,66}; ????????????//?以字節(jié)流的形式將data里的數(shù)據(jù)寫入到輸出流 ????????????fis.write(all); ????????????fis.close();? ????????}catch(IOException?e){ ????????????e.printStackTrace(); ????????} ????}}1234567891011121314151617
我們打開對(duì)應(yīng)的文件,發(fā)現(xiàn)數(shù)據(jù)就已經(jīng)寫在里面了,但是輸出流跟輸入流有一個(gè)區(qū)別,就是輸出流的時(shí)候不一定要求文件存在,當(dāng)文件不存在的時(shí)候,會(huì)自動(dòng)給我們創(chuàng)建一個(gè)新的文件,而輸入流則會(huì)拋出異常
字符流:就是在字節(jié)流的基礎(chǔ)上,加上編碼,形成的數(shù)據(jù)流
字符流分為字符輸入流Reader 和 字符輸出流 Writer
他們常用的子類就是FileReader 和 FileWriter
在之前我們使用了字節(jié)輸入流讀取文件中的內(nèi)容,讀取的AB打印出來是65和66
現(xiàn)在我們來看一下使用字符輸入流讀取文件是什么樣的結(jié)果
public?class?Test?{ ? ????public?static?void?main(String[]?args)?{ ????????//?準(zhǔn)備文件hello.txt其中的內(nèi)容是AB ????????File?f?=?new?File("d:/hello.txt"); ????????//?創(chuàng)建基于文件的Reader ????????try?(FileReader?fr?=?new?FileReader(f))?{ ????????????//?創(chuàng)建字符數(shù)組,其長度就是文件的長度 ????????????char[]?all?=?new?char[(int)?f.length()]; ????????????//?以字符流的形式讀取文件所有內(nèi)容 ????????????fr.read(all); ????????????for?(char?b?:?all)?{ ????????????????//?打印出來是A?B ????????????????System.out.println(b); ????????????} ????????}?catch?(IOException?e)?{ ????????????//?TODO?Auto-generated?catch?block ????????????e.printStackTrace(); ????????} ? ????}}12345678910111213141516171819202122
字符輸入流可以直接讀取文件中的字符
我們可以直接將一串字符存儲(chǔ)到文件中,代碼如下:
public?class?Test{ ????public?static?void?main(String[]?args){ ????????//?創(chuàng)建文件對(duì)象,文件內(nèi)容是空的 ????????File?f?=?new?File("D:/hello.txt"); ????????//?要寫入的字符串 ????????String?str?=?"hello"; ?????? char[]?cs?=?str.toCharArray(); ????????try(FileWrter?fw?=?new?FileWriter(f)){ ????????????fw.write(cs) ????????}catch(IOException?e){ ????????????e.printStackTrace(); ????????} ????}}1234567891011121314
文件中的內(nèi)容就會(huì)變稱hello
上面我們學(xué)習(xí)了字節(jié)流和字符流,那么我們分別用兩種流來從文件中讀取漢字內(nèi)容。
首先你得了解文本是以哪種編碼方式進(jìn)行保存的
使用字節(jié)流讀取文本后,再使用對(duì)應(yīng)的編碼方式去識(shí)別這些文字
public?class?Test{ ????File?f?=?new?File("D:/hello.txt"); ????try(FileInputStream?fis?=?new?FileInputStream(f)){ ????????byte[]?all?=?new?byte[(int)?f.length()]; ????????fis.read(all); ????????//將讀到的字節(jié)進(jìn)行編碼輸出 ????????String?str?=?new?String(all,"GBK"); ????????System.out.println(str); ????}catch(IOException?e){ ????????e.printStackTrace(); ????}}123456789101112
FileReader得到的字符,肯定是已經(jīng)把字節(jié)根據(jù)某種編碼方式識(shí)別成的字符。
FIleReader的編碼方式可以用Charset.defaultCharset()獲取,如果是中文的操作系統(tǒng)那么就是GBK
假設(shè)現(xiàn)在我們的文件是用UTF-8編碼方式保存的,那么我們?cè)撊绾问褂米址髯x取文字呢?
答案就是使用InputStreamReader,這個(gè)是字節(jié)流到字符流的橋接器,它可以按照指定的字符集讀取字節(jié)并將它們轉(zhuǎn)換為字符。
public?class?TestStream?{ ????public?static?void?main(String[]?args)?throws?UnsupportedEncodingException,?FileNotFoundException?{ ????????File?f?=?new?File("D:/hello.txt"); ????????System.out.println("默認(rèn)編碼方式:"+Charset.defaultCharset()); ????????//FileReader得到的是字符,所以一定是已經(jīng)把字節(jié)根據(jù)某種編碼識(shí)別成了字符了 ????????//而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統(tǒng),就是GBK ????????try?(FileReader?fr?=?new?FileReader(f))?{ ????????????char[]?cs?=?new?char[(int)?f.length()]; ????????????fr.read(cs); ????????????System.out.printf("FileReader會(huì)使用默認(rèn)的編碼方式%s,識(shí)別出來的字符是:%n",Charset.defaultCharset()); ????????????System.out.println(new?String(cs)); ????????}?catch?(IOException?e)?{ ????????????//?TODO?Auto-generated?catch?block ????????????e.printStackTrace(); ????????} ????????//FileReader是不能手動(dòng)設(shè)置編碼方式的,為了使用其他的編碼方式,只能使用InputStreamReader來代替 ????????//并且使用new?InputStreamReader(new?FileInputStream(f),Charset.forName("UTF-8"));?這樣的形式 ????????try?(InputStreamReader?isr?=?new?InputStreamReader(new?FileInputStream(f),Charset.forName("UTF-8")))?{ ????????????char[]?cs?=?new?char[(int)?f.length()]; ????????????isr.read(cs); ????????????System.out.printf("InputStreamReader?指定編碼方式UTF-8,識(shí)別出來的字符是:%n"); ????????????System.out.println(new?String(cs)); ????????}?catch?(IOException?e)?{ ????????????//?TODO?Auto-generated?catch?block ????????????e.printStackTrace(); ????????} ????????? ????}}1234567891011121314151617181920212223242526272829
為什么中字的前面有一個(gè)?,如果你是用記事本另存為UTF-8的字符集編碼的話,那么在第一個(gè)字節(jié)有一個(gè)標(biāo)識(shí),叫做BOM,用來標(biāo)識(shí)這個(gè)文件是使用UTF-8編碼的
以介質(zhì)是硬盤為例,字節(jié)流和字符流的弊端:
在每一次讀寫的時(shí)候,都會(huì)訪問硬盤。 如果讀寫的頻率比較高的時(shí)候,其性能表現(xiàn)不佳。
為了解決以上弊端,采用緩存流。
緩存流在讀取的時(shí)候,會(huì)一次性讀較多的數(shù)據(jù)到緩存中,以后每一次的讀取,都是在緩存中訪問,直到緩存中的數(shù)據(jù)讀取完畢,再到硬盤中讀取。
就好比吃飯,不用緩存就是每吃一口都到鍋里去鏟。用緩存就是先把飯盛到碗里,碗里的吃完了,再到鍋里去鏟
緩存流在寫入數(shù)據(jù)的時(shí)候,會(huì)先把數(shù)據(jù)寫入到緩存區(qū),直到緩存區(qū)達(dá)到一定的量,才把這些數(shù)據(jù),一起寫入到硬盤中去。按照這種操作模式,就不會(huì)像字節(jié)流,字符流那樣每寫一個(gè)字節(jié)都訪問硬盤,從而減少了IO操作
BufferedReader可以一次性讀取一行數(shù)據(jù)
public?class?Test{ ????public?static?void?main(String[]?args){ ????????/** ????????準(zhǔn)備一個(gè)文件,里面的內(nèi)容是 ????????hello ????????world ????????你好 ????????*/ ????????File?f?=?new?File("d:/hello.txt"); ????????//?緩存字符輸入流必須在一個(gè)存在的流的基礎(chǔ)上創(chuàng)建 ????????try( ????????FileReader?fr?=?new?FileReader(f); ????????BufferedReader?br?=?new?BufferedReader(fr); ????????????){ ????????????while(true){ ????????????????//?一次讀取一行 ????????????????String?line?=?br.readLine(); ????????????????if(line?==?null){ ????????????????????break; ????????????????} ????????????????System.out.println(line); ????????????}catch(IOException?e){ ????????????????e.printStackTrace(); ????????????} ????????} ????}}123456789101112131415161718192021222324252627
PrintWrite,可以一次寫出一行數(shù)據(jù)
public?class?TestStream?{ ??? ????public?static?void?main(String[]?args)?{ ????????//?向文件lol2.txt中寫入三行語句 ????????File?f?=?new?File("d:/hello.txt"); ?????????? ????????try?(?????????? ????????????????PrintWriter?pw?=?new?PrintWriter(f);?????????????? ????????)?{ ????????????pw.println("hello"); ????????????pw.println("world"); ????????????pw.println("你好"); ????????}?catch?(IOException?e)?{ ????????????//?TODO?Auto-generated?catch?block ????????????e.printStackTrace(); ????????} ??? ????}}12345678910111213141516171819
這里需要注意的是,緩存字符輸入流的構(gòu)造方法的參數(shù)是一個(gè)Reader,也就是一個(gè)字符流,而PrintWriter的構(gòu)造參數(shù)可以是文件對(duì)象也可以是字節(jié)流或者字符流對(duì)象!
分別是BufferedInputStream 和 BufferedOutputStream
下面代碼演示的是通過緩存字節(jié)輸入流和輸出流實(shí)現(xiàn)文件的復(fù)制
public?class?Test{ ????public?static?void?main(String[]?args){ ????????File?file?=?new?File("E:/我的文檔/臨時(shí)文件/視屏文件.ts"); ????????File?file1?=?new?File("E:/我的文檔/臨時(shí)文件/視屏文件(副本).ts"); ????????try?( ????????????????FileInputStream?fis?=?new?FileInputStream(f); ????????????????FileOutputStream?fos?=?new?FileOutputStream(f1); ????????????????BufferedInputStream?bis?=?new?BufferedInputStream(fis); ????????????????BufferedOutputStream?bos?=?new?BufferedOutputStream(fos); ????????){ ????????????byte[]?bytes?=?new?byte[1024]; ????????????int?len; ????????????while(true){ ????????????????len?=?bis.read(bytes); ????????????????if(len?==?-1){ ????????????????????break; ????????????????} ????????????????bos.write(bytes,0,len); ????????????} ????????}catch?(IOException?e){ ????????????e.printStackTrace(); ????????} ????} ????}}
Java
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。