一锅减,字節(jié)輸出流OutputStream
OutputStream此抽象類辐董,是表示輸出字節(jié)流的所有類的超類扫尖。操作的數(shù)據(jù)都是字節(jié)白对,定義了輸出字節(jié)流的基本共性功能方法。輸出流中定義都是寫write方法换怖,如下圖:
1.1FileOutputStream類
OutputStream有很多子類甩恼,其中子類FileOutputStream可用來(lái)寫入數(shù)據(jù)到文件。
FileOutputStream類沉颂,即文件輸出流条摸,是用于將數(shù)據(jù)寫入File的輸出流。
FileOutputStream類寫入數(shù)據(jù)到文件中
將數(shù)據(jù)寫到文件中铸屉,代碼演示:
public class FileOutputStreamDemo {
??? public static void main(String[] args) throws IOException {
??? ??? //需求:將數(shù)據(jù)寫入到文件中钉蒲。
??? ??? //創(chuàng)建存儲(chǔ)數(shù)據(jù)的文件。
??? ??? Filefile =new File("c:\\file.txt");
??? ??? //創(chuàng)建一個(gè)用于操作文件的字節(jié)輸出流對(duì)象彻坛。一創(chuàng)建就必須明確數(shù)據(jù)存儲(chǔ)目的地顷啼。
??? ??? //輸出流目的是文件,會(huì)自動(dòng)創(chuàng)建昌屉。如果文件存在钙蒙,則覆蓋。
??? ??? FileOutputStreamfos =new FileOutputStream(file);
??? ??? //調(diào)用父類中的write方法间驮。
??? ??? byte[] data = "abcde".getBytes();
??? ??? fos.write(data);
??? ??? //關(guān)閉流資源躬厌。
??? ??? fos.close();
??? }
}
給文件中續(xù)寫和換行
我們直接new FileOutputStream(file)這樣創(chuàng)建對(duì)象,寫入數(shù)據(jù)竞帽,會(huì)覆蓋原有的文件扛施,那么我們想在原有的文件中續(xù)寫內(nèi)容怎么辦呢?繼續(xù)查閱FileOutputStream的API屹篓。發(fā)現(xiàn)在FileOutputStream的構(gòu)造函數(shù)中煮嫌,可以接受一個(gè)boolean類型的值,如果值true抱虐,就會(huì)在文件末位繼續(xù)添加昌阿。構(gòu)造方法
給文件中續(xù)寫數(shù)據(jù)和換行,代碼演示:
public class FileOutputStreamDemo2 {
??? public static void main(String[] args) throws Exception {
??? ??? Filefile =new File("c:\\file.txt");
??? ??? FileOutputStream??? fos =new FileOutputStream(file,true);
??? ??? Stringstr ="\r\n" +"";
??? ??? fos.write(str.getBytes());
??? ??? fos.close();
??? }
}
1.2字節(jié)輸入流InputStream
通過(guò)前面的學(xué)習(xí)恳邀,我們可以把內(nèi)存中的數(shù)據(jù)寫出到文件中懦冰,那如何想把硬盤中的數(shù)據(jù)讀到內(nèi)存中,我們通過(guò)InputStream可以實(shí)現(xiàn)谣沸。InputStream此抽象類刷钢,是表示字節(jié)輸入流的所有類的超類。乳附,定義了字節(jié)輸入流的基本共性功能方法
int read():讀取一個(gè)字節(jié)并返回内地,沒(méi)有字節(jié)返回-1.
int read(byte[]): 讀取一定量的字節(jié)數(shù)伴澄,并存儲(chǔ)到字節(jié)數(shù)組中,返回讀取到的字節(jié)數(shù)阱缓。
InputStream有很多子類非凌,其中子類FileInputStream可用來(lái)讀取文件內(nèi)容。
FileInputStream 從文件系統(tǒng)中的某個(gè)文件中獲得輸入字節(jié)荆针。
FileInputStream類讀取數(shù)據(jù)read方法:在讀取文件中的數(shù)據(jù)時(shí)敞嗡,調(diào)用read方法,實(shí)現(xiàn)從文件中讀取數(shù)據(jù)
public class FileInputStreamDemo {
??? public static void main(String[] args) throws IOException {
??? ??? Filefile =new File("c:\\file.txt");
??? ??? //創(chuàng)建一個(gè)字節(jié)輸入流對(duì)象,必須明確數(shù)據(jù)源航背,其實(shí)就是創(chuàng)建字節(jié)讀取流和數(shù)據(jù)源相關(guān)聯(lián)喉悴。
??? ??? FileInputStreamfis =new FileInputStream(file);
??? ??? //讀取數(shù)據(jù)。使用 read();一次讀一個(gè)字節(jié)玖媚。
??? ??? int ch = 0;
??? ??? while((ch=fis.read())!=-1){
??? ??? ??? System.out.println("ch="+(char)ch);
??? ??? // 關(guān)閉資源箕肃。
??? ??? fis.close();
??? }
}
讀取數(shù)據(jù)read(byte[])方法
在讀取文件中的數(shù)據(jù)時(shí),調(diào)用read方法今魔,每次只能讀取一個(gè)突雪,太麻煩了,于是我們可以定義數(shù)組作為臨時(shí)的存儲(chǔ)容器涡贱,這時(shí)可以調(diào)用重載的read方法,一次可以讀取多個(gè)字符
public class FileInputStreamDemo2 {
??? public static void main(String[] args) throws IOException {
??? ??? Filefile =new File("c:\\file.txt");??? //演示第二個(gè)讀取方法惹想,read(byte[]);
??? ?? // 創(chuàng)建一個(gè)字節(jié)輸入流對(duì)象,必須明確數(shù)據(jù)源问词,其實(shí)就是創(chuàng)建字節(jié)讀取流和數(shù)據(jù)源相關(guān)聯(lián)。
??? ??? FileInputStreamfis =newFileInputStream(file);?? ???
??? ??? //創(chuàng)建一個(gè)字節(jié)數(shù)組嘀粱。
??? ??? byte[] buf = new byte[1024];//長(zhǎng)度可以定義成1024的整數(shù)倍激挪。?? ???
??? ??? int len = 0;
??? ??? while((len=fis.read(buf))!=-1){
??? ??? ??? System.out.println(new String(buf,0,len));
??? ??? }
??? ??? fis.close();
??? }
復(fù)制文件
原理;讀取一個(gè)已有的數(shù)據(jù)锋叨,并將這些讀到的數(shù)據(jù)寫入到另一個(gè)文件中
public class CopyFileTest {
??? public static void main(String[] args) throws IOException {
??? ??? //1,明確源和目的垄分。
??? ??? FilesrcFile =new File("c:\\YesDir\test.JPG");
??? ??? FiledestFile =new File("copyTest.JPG");
??? ??? //2,明確字節(jié)流 輸入流和源相關(guān)聯(lián),輸出流和目的關(guān)聯(lián)娃磺。
??? ??? FileInputStreamfis =new FileInputStream(srcFile);
??? ??? FileOutputStreamfos =new FileOutputStream(destFile);
??? ??? //3, 使用輸入流的讀取方法讀取字節(jié)薄湿,并將字節(jié)寫入到目的中。
??? ??? int ch = 0;
??? ??? while((ch=fis.read())!=-1){
??? ??? ??? fos.write(ch);
??? ??? }
??? ??? //4,關(guān)閉資源偷卧。
??? ??? fos.close();
??? ??? fis.close();
??? }
}
上述代碼輸入流和輸出流之間是通過(guò)ch這個(gè)變量進(jìn)行數(shù)據(jù)交換的豺瘤。上述復(fù)制文件有個(gè)問(wèn)題,每次都從源文件讀取一個(gè)听诸,然后在寫到指定文件坐求,接著再讀取一個(gè)字符,然后再寫一個(gè)晌梨,一直這樣下去桥嗤。效率極低
緩沖數(shù)組方式復(fù)制文件
上述代碼復(fù)制文件效率太低了须妻,并且頻繁的從文件讀數(shù)據(jù),和寫數(shù)據(jù)泛领,能不能一次多把文件中多個(gè)數(shù)據(jù)都讀進(jìn)內(nèi)容中荒吏,然后在一次寫出去,這樣的速度一定會(huì)比前面代碼速度快师逸。
public class CopyFileByBufferTest {
??? public static void main(String[] args) throws IOException {
??? ??? FilesrcFile =new File("c:\\YesDir\test.JPG");
??? ??? FiledestFile =new File("copyTest.JPG");
??? ??? // 明確字節(jié)流 輸入流和源相關(guān)聯(lián)司倚,輸出流和目的關(guān)聯(lián)。
??? ??? FileInputStreamfis =new FileInputStream(srcFile);
??? ??? FileOutputStreamfos =new FileOutputStream(destFile);
??? ??? //定義一個(gè)緩沖區(qū)篓像。
??? ??? byte[] buf = new byte[1024];
??? ??? int len = 0;
??? ??? while ((len = fis.read(buf))!= -1) {
??? ??? ??? fos.write(buf, 0, len);// 將數(shù)組中的指定長(zhǎng)度的數(shù)據(jù)寫入到輸出流中动知。
??? ??? }
??? ??? // 關(guān)閉資源。
??? ??? fos.close();
??? ??? fis.close();
??? }
}
二员辩,字符流
經(jīng)過(guò)前面的學(xué)習(xí)盒粮,我們基本掌握的文件的讀寫操作,在操作過(guò)程中字節(jié)流可以操作所有數(shù)據(jù)奠滑,可是當(dāng)我們操作的文件中有中文字符丹皱,并且需要對(duì)中文字符做出處理時(shí)怎么辦呢?
字節(jié)流讀取字符的問(wèn)題
通過(guò)以下程序讀取帶有中文件的文件宋税。?
public class CharStreamDemo {
??? public static void main(String[] args) throws IOException {
??? ??? //給文件中寫中文
??? ??? writeCNText();
??? ??? //讀取文件中的中文
??? ??? readCNText();
??? }??
??? //讀取中文
??? public static void readCNText() throws IOException {
??? ??? FileInputStreamfis=new FileInputStream("c:\\cn.txt");
??? ??? int ch = 0;
??? ??? while((ch =fis.read())!=-1){
??? ??? ??? System.out.println(ch);
??? ??? }
??? }
??? //寫中文
??? public static void writeCNText() throws IOException {
??? ??? FileOutputStreamfos =new FileOutputStream("c:\\cn.txt");
??? ??? fos.write("a歡迎你".getBytes());
??? ??? fos.close();
??? }
}
上面程序在讀取含有中文的文件時(shí)摊崭,我們并沒(méi)有看到具體的中文,而是看到一些數(shù)字杰赛,這是什么原因呢呢簸?既然看不到中文,那么我們?nèi)绾螌?duì)其中的中文做處理呢乏屯?要解決這個(gè)問(wèn)題根时,我們必須研究下字符的編碼過(guò)程。
字符編碼表
我們知道計(jì)算機(jī)底層數(shù)據(jù)存儲(chǔ)的都是二進(jìn)制數(shù)據(jù)辰晕,而我們生活中的各種各樣的數(shù)據(jù)蛤迎,如何才能和計(jì)算機(jī)中存儲(chǔ)的二進(jìn)制數(shù)據(jù)對(duì)應(yīng)起來(lái)呢?
這時(shí)老美他們就把每一個(gè)字符和一個(gè)整數(shù)對(duì)應(yīng)起來(lái)含友,就形成了一張編碼表替裆,老美他們的編碼表就是ASCII表。其中就是各種英文字符對(duì)應(yīng)的編碼窘问。
編碼表:其實(shí)就是生活中字符和計(jì)算機(jī)二進(jìn)制的對(duì)應(yīng)關(guān)系表扎唾。
1、ascii:一個(gè)字節(jié)中的7位就可以表示南缓。對(duì)應(yīng)的字節(jié)都是正數(shù)胸遇。0-xxxxxxx
2、iso-8859-1:拉丁碼表 latin汉形,用了一個(gè)字節(jié)用的8位纸镊。1-xxxxxxx? 負(fù)數(shù)倍阐。
3、GB2312:簡(jiǎn)體中文碼表逗威。包含6000-7000中文和符號(hào)峰搪。用兩個(gè)字節(jié)表示。兩個(gè)字節(jié)第一個(gè)字節(jié)是負(fù)數(shù),第二個(gè)字節(jié)可能是正數(shù)
GBK:目前最常用的中文碼表凯旭,2萬(wàn)的中文和符號(hào)概耻。用兩個(gè)字節(jié)表示,其中的一部分文字罐呼,第一個(gè)字節(jié)開(kāi)頭是1鞠柄,第二字節(jié)開(kāi)頭是0
GB18030:最新的中文碼表,目前還沒(méi)有正式使用嫉柴。
unicode:國(guó)際標(biāo)準(zhǔn)碼表:無(wú)論是什么文字厌杜,都用兩個(gè)字節(jié)存儲(chǔ)。
Java中的char類型用的就是這個(gè)碼表计螺。char c = 'a';占兩個(gè)字節(jié)夯尽。
Java中的字符串是按照系統(tǒng)默認(rèn)碼表來(lái)解析的。簡(jiǎn)體中文版 字符串默認(rèn)的碼表是GBK登馒。
5匙握、UTF-8:基于unicode,一個(gè)字節(jié)就可以存儲(chǔ)數(shù)據(jù)陈轿,不要用兩個(gè)字節(jié)存儲(chǔ)圈纺,而且這個(gè)碼表更加的標(biāo)準(zhǔn)化,在每一個(gè)字節(jié)頭加入了編碼信息(后期到api中查找)济欢。
能識(shí)別中文的碼表:GBK、UTF-8小渊;正因?yàn)樽R(shí)別中文碼表不唯一法褥,涉及到了編碼解碼問(wèn)題。
對(duì)于我們開(kāi)發(fā)而言酬屉;常見(jiàn)的編碼GBK? UTF-8? ISO-8859-1
文字--->(數(shù)字) :編碼半等。“abc”.getBytes()? byte[]
(數(shù)字)--->文字? :解碼呐萨。byte[] b={97,98,99}? newString(b)
1.1字符輸入流Reader
上述程序中我們讀取擁有中文的文件時(shí)杀饵,使用的字節(jié)流在讀取,那么我們讀取到的都是一個(gè)一個(gè)字節(jié)谬擦。只要把這些字節(jié)去查閱對(duì)應(yīng)的編碼表切距,就能夠得到與之對(duì)應(yīng)的字符。API中是否給我們已經(jīng)提供了讀取相應(yīng)字符的功能流對(duì)象惨远,Reader谜悟,讀取字符流的抽象超類
read():讀取單個(gè)字符并返回
read(char[]):將數(shù)據(jù)讀取到數(shù)組中话肖,并返回讀取的個(gè)數(shù)。
FileReader類
查閱FileInputStream的API葡幸,發(fā)現(xiàn)FileInputStream 用于讀取諸如圖像數(shù)據(jù)之類的原始字節(jié)流最筒。要讀取字符流,請(qǐng)考慮使用 FileReader蔚叨。打開(kāi)FileReader的API介紹床蜘。用來(lái)讀取字符文件的便捷類。此類的構(gòu)造方法假定默認(rèn)字符編碼和默認(rèn)字節(jié)緩沖區(qū)大小都是適當(dāng)?shù)?/p>
FileReader讀取包含中文的文件
使用FileReader讀取包含中文的文件
public class CharStreamDemo {
??? public static void main(String[] args) throws IOException {
??? ??? //給文件中寫中文
??? ??? writeCNText();
??? ??? //讀取文件中的中文
??? ??? readCNText();
??? }??
??? //讀取中文
??? public static void readCNText() throws IOException {
??? ??? FileReaderfr =new FileReader("D:\\test\\cn.txt");
??? ??? int ch = 0;
??? ??? while((ch = fr.read())!=-1){
??? ??? ??? //輸出的字符對(duì)應(yīng)的編碼值
??? ??? ??? System.out.println(ch);
??? ??? ??? //輸出字符本身
??? ??? ??? System.out.println((char)ch);
??? ??? }
??? }
??? //寫中文
??? public static void writeCNText() throws IOException {
??? ??? FileOutputStreamfos =new FileOutputStream("D:\\test\\cn.txt");
??? ??? fos.write("a尚觀歡迎你".getBytes());
??? ??? fos.close();
??? }
1.2字符輸出流Writer
既然有專門用于讀取字符的流對(duì)象蔑水,那么肯定也有寫的字符流對(duì)象邢锯,查閱API,發(fā)現(xiàn)有一個(gè)Writer類肤粱,Writer是寫入字符流的抽象類弹囚。其中描述了相應(yīng)的寫的動(dòng)作
FileWriter類
查閱FileOutputStream的API,發(fā)現(xiàn)FileOutputStream 用于寫入諸如圖像數(shù)據(jù)之類的原始字節(jié)的流领曼。要寫入字符流鸥鹉,請(qǐng)考慮使用 FileWriter。打開(kāi)FileWriter的API介紹庶骄。用來(lái)寫入字符文件的便捷類毁渗。此類的構(gòu)造方法假定默認(rèn)字符編碼和默認(rèn)字節(jié)緩沖區(qū)大小都是可接受的。
FileWriter寫入中文到文件中
寫入字符到文件中单刁,先進(jìn)行流的刷新灸异,再進(jìn)行流的關(guān)閉。
public class FileWriterDemo {
??? public static void main(String[] args) throws IOException {
??? ??? //演示FileWriter 用于操作文件的便捷類羔飞。
??? ??? FileWriterfw =new FileWriter("d:\\text\\fw.txt");
??? ??? fw.write("你好謝謝再見(jiàn)");//這些文字都要先編碼肺樟。都寫入到了流的緩沖區(qū)中。
??? ??? fw.flush();
??? ??? fw.close();
??? }
}
復(fù)制文本文件
練習(xí):復(fù)制文本文件逻淌。
思路:
1么伯,既然是文本涉及編碼表。需要用字符流卡儒。
2田柔,操作的是文件。涉及硬盤骨望。
3硬爆,有指定碼表嗎?沒(méi)有擎鸠,默認(rèn)就行缀磕。
操作的是文件,使用的默認(rèn)碼表。使用哪個(gè)字符流對(duì)象虐骑。直接使用字符流操作文件的便捷類准验。FileReader? FileWriter
public class CopyTextFileTest {
??? public static void main(String[] args) throws IOException {
??? ??? copyTextFile();
??? }
??? public static void copyTextFile() throws IOException {
??? ??? //1,明確源和目的。
??? ??? FileReaderfr =new FileReader("c:\\cn.txt");
??? ??? FileWriterfw =new FileWriter("c:\\copy.txt");
??? ??? //2,為了提高效率廷没。自定義緩沖區(qū)數(shù)組糊饱。字符數(shù)組。
??? ??? char[] buf = new char[1024];
??? ??? int len = 0;
??? ??? while((len=fr.read(buf))!=-1){
??? ??? ??? fw.write(buf,0,len);
??? ??? }
??? ??? /*2,循環(huán)讀寫操作颠黎。效率低另锋。
??? ??? intch=0;
??? ??? while((ch=fr.read())!=-1){
??? ??? ??? fw.write(ch);
??? ??? }
??? ??? */
??? ??? //3,關(guān)閉資源。
??? ??? fw.close();
??? ??? fr.close();
??? }
}