1 字節(jié)流
??在前面的學習過程中旦事,我們一直都是在操作文件或者文件夾,并沒有給文件中寫任何數(shù)據(jù)〖泵穑現(xiàn)在我們就要開始給文件中寫數(shù)據(jù)姐浮,或者讀取文件中的數(shù)據(jù)。
1.1 字節(jié)輸出流OutputStream
??OutputStream此抽象類葬馋,是表示輸出字節(jié)流的所有類的超類卖鲤。操作的數(shù)據(jù)都是字節(jié)肾扰,定義了輸出字節(jié)流的基本共性功能方法。
??輸出流中定義都是寫write方法蛋逾,如下圖:
1.1.1 FileOutputStream類
??OutputStream有很多子類集晚,其中子類FileOutputStream可用來寫入數(shù)據(jù)到文件。FileOutputStream類区匣,即文件輸出流偷拔,是用于將數(shù)據(jù)寫入 File的輸出流。
構(gòu)造方法
1.1.2 FileOutputStream類寫入數(shù)據(jù)到文件中
將數(shù)據(jù)寫到文件中
package com.qtw.api;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 字節(jié)輸出流
* java.io.OutputStream所有字節(jié)輸出流的超類
* 作用:從java程序?qū)懗鑫募?* 字節(jié):這樣的流每次文件中的1個字節(jié)
* 寫任意文件
*
* 方法都是寫入的方法
*
* write(int b) 寫入1個字節(jié)
* write(byte[] b) 寫入字節(jié)數(shù)組
* write(byte[] b,int,int) 寫入字節(jié)數(shù)組沉颂,int 開始寫入的索引条摸,int寫幾個
* close()方法悦污,關閉流對象铸屉,釋放此次流相關的資源
*
* 流對象,操作文件的時候切端,自己不做彻坛,依賴操作系統(tǒng)
*
*FileOutputStream
* 寫入數(shù)據(jù)文件,學習父類方法踏枣,使用子類對象
*
* 子類的構(gòu)造方法:作用:綁定輸出的輸出源
* 參數(shù)
* File 文件對象
* String 字符串的文件名
* 流對象使用步驟:
* 1.創(chuàng)建流子類的對象昌屉,綁定數(shù)據(jù)源
* 2.調(diào)用對象的方法write()寫入
* 3.close釋放資源
* 流對象的構(gòu)造方法可以創(chuàng)建文件,如果文件存在直接覆蓋
* */
public class TestDemo {
public static void main(String[] args) throws IOException{
FileOutputStream fos = new FileOutputStream("e:\\test\\a.txt");
//寫入1個字節(jié)
fos.write(100);
//關閉資源
fos.close();
//寫入字節(jié)數(shù)組
FileOutputStream fos1 = new FileOutputStream("e:\\test\\b.txt");
byte[] arr = {97,98,99,100};
fos1.write(arr);
//寫入字節(jié)數(shù)組的一部分
fos1.write(arr,1,2);
fos1.close();
//寫入字符串的簡便方法
FileOutputStream fos2 = new FileOutputStream("e:\\test\\c.txt");
String s = "Hello World";
fos2.write(s.getBytes());
fos2.close();
}
}
1.1.3 給文件中續(xù)寫和換行
??我們直接new FileOutputStream(file)這樣創(chuàng)建對象茵瀑,寫入數(shù)據(jù)间驮,會覆蓋原有的文件,那么我們想在原有的文件中續(xù)寫內(nèi)容怎么辦呢马昨?
??繼續(xù)查閱FileOutputStream的API竞帽。發(fā)現(xiàn)在FileOutputStream的構(gòu)造函數(shù)中,可以接受一個boolean類型的值鸿捧,如果值true屹篓,就會在文件末位繼續(xù)添加。
構(gòu)造方法
給文件中續(xù)寫數(shù)據(jù)和換行匙奴,代碼演示:
package com.qtw.api;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws Exception {
File file = new File("e:\\test\\a.txt");
FileOutputStream fos = new FileOutputStream(file, true);
String str = "\r\n"+"Message ok";
fos.write(str.getBytes());
fos.close();
}
}
1.1.4 IO異常的處理
??在前面編寫代碼中都發(fā)生了IO的異常堆巧。我們在實際開發(fā)中,對異常時如何處理的泼菌,我們來演示一下谍肤。
package com.qtw.api;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) {
File file = new File("e:\\test\\a.txt");
//定義FileOutputStream的引用
FileOutputStream fos = null;
try {
//創(chuàng)建FileOutputStream對象
fos = new FileOutputStream(file);
//寫出數(shù)據(jù)
fos.write("abcde".getBytes());
} catch (IOException ex) {
System.out.println(ex.toString());
throw new RuntimeException("文件寫入失敗,重試");
} finally {
//一定要判斷fos是否為null哗伯,只有不為null時荒揣,才可以關閉資源
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("文件釋放資源失敗");
}
}
}
}
}
1.2 字節(jié)輸入流InputStream
??通過前面的學習,我們可以把內(nèi)存中的數(shù)據(jù)寫出到文件中笋颤,那如何想把內(nèi)存中的數(shù)據(jù)讀到內(nèi)存中乳附,我們通過InputStream可以實現(xiàn)内地。InputStream此抽象類,是表示字節(jié)輸入流的所有類的超類赋除。阱缓,定義了字節(jié)輸入流的基本共性功能方法。
int read():讀取一個字節(jié)并返回举农,沒有字節(jié)返回-1荆针。
int read(byte[]): 讀取一定量的字節(jié)數(shù),并存儲到字節(jié)數(shù)組中颁糟,返回讀取到的字節(jié)數(shù)航背,沒有字節(jié)返回-1。
1.2.1 FileInputStream類
??InputStream有很多子類棱貌,其中子類FileInputStream可用來讀取文件內(nèi)容玖媚。
??FileInputStream 從文件系統(tǒng)中的某個文件中獲得輸入字節(jié)。
構(gòu)造方法
1.2.2 FileInputStream類讀取數(shù)據(jù)read方法
在讀取文件中的數(shù)據(jù)時婚脱,調(diào)用read方法今魔,實現(xiàn)從文件中讀取數(shù)據(jù)
從文件中讀取數(shù)據(jù),代碼演示:
package com.qtw.api;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException{
File file = new File("e:\\test\\a.txt");
//創(chuàng)建一個字節(jié)輸入流對象,必須明確數(shù)據(jù)源障贸,其實就是創(chuàng)建字節(jié)讀取流和數(shù)據(jù)源相關聯(lián)错森。
FileInputStream fis = new FileInputStream(file);
//讀取數(shù)據(jù)。使用 read();一次讀一個字節(jié)篮洁。
int ch = 0;
while((ch=fis.read())!=-1){
System.out.println("ch="+(char)ch);
}
fis.close();
}
}
1.2.3 FileInputStream類讀取數(shù)據(jù)read(byte[])方法
??在讀取文件中的數(shù)據(jù)時涩维,調(diào)用read方法,每次只能讀取一個袁波,太麻煩了瓦阐,于是我們可以定義數(shù)組作為臨時的存儲容器,這時可以調(diào)用重載的read方法锋叨,一次可以讀取多個字符垄分。
package com.qtw.api;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException{
/*
* 演示第二個讀取方法, read(byte[]);
*/
File file = new File("e:\\test\\a.txt");
// 創(chuàng)建一個字節(jié)輸入流對象,必須明確數(shù)據(jù)源娃磺,其實就是創(chuàng)建字節(jié)讀取流和數(shù)據(jù)源相關聯(lián)薄湿。
FileInputStream fis = new FileInputStream(file);
//創(chuàng)建一個字節(jié)數(shù)組。
byte[] buf = new byte[2];
int len = 0;
while((len=fis.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
fis.close();
}
}
1.3 字節(jié)流練習
??既然會了文件的讀和寫操作了偷卧,那么我們就要在這個基礎上進行更為復雜的操作豺瘤。使用讀寫操作完成文件的復制。
1.3.1 復制文件
??原理听诸;讀取一個已有的數(shù)據(jù)坐求,并將這些讀到的數(shù)據(jù)寫入到另一個文件中。
循環(huán)復制單個字符TestDemo.java
package com.qtw.api;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException{
//1,明確源和目的晌梨。
File srcFile = new File("e:\\test\\timg.jpg");
File destFile = new File("e:\\test\\a.jpg");
//2,明確字節(jié)流 輸入流和源相關聯(lián)桥嗤,輸出流和目的關聯(lián)须妻。
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//3, 使用輸入流的讀取方法讀取字節(jié),并將字節(jié)寫入到目的中泛领。
int ch = 0;
while((ch=fis.read())!=-1){
fos.write(ch);
}
//4,關閉資源荒吏。
fos.close();
fis.close();
}
}
??上述代碼輸入流和輸出流之間是通過ch這個變量進行數(shù)據(jù)交換的。
??上述復制文件有個問題渊鞋,每次都從源文件讀取一個绰更,然后在寫到指定文件,接著再讀取一個字符锡宋,然后再寫一個儡湾,一直這樣下去。效率極低执俩。
復制任何文件都行徐钠,ex:QQ.exe,因為所有的程序本質(zhì)都是字節(jié)
1.3.2 緩沖數(shù)組方式復制文件
??上述代碼復制文件效率太低了奠滑,并且頻繁的從文件讀數(shù)據(jù)丹皱,和寫數(shù)據(jù)妒穴,能不能一次多把文件中多個數(shù)據(jù)都讀進內(nèi)容中宋税,然后在一次寫出去,這樣的速度一定會比前面代碼速度快讼油。
package com.qtw.api;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException{
File srcFile = new File("e:\\test\\timg.jpg");
File destFile = new File("e:\\test\\b.jpg");
// 明確字節(jié)流 輸入流和源相關聯(lián)杰赛,輸出流和目的關聯(lián)。
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//定義一個緩沖區(qū)矮台。
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);// 將數(shù)組中的指定長度的數(shù)據(jù)寫入到輸出流中乏屯。
}
// 關閉資源。
fos.close();
fis.close();
}
}
2 字符流
??經(jīng)過前面的學習瘦赫,我們基本掌握的文件的讀寫操作辰晕,在操作過程中字節(jié)流可以操作所有數(shù)據(jù),可是當我們操作的文件中有中文字符确虱,并且需要對中文字符做出處理時怎么辦呢含友?
2.1 字節(jié)流讀取字符的問題
通過以下程序讀取帶有中文件的文件
package com.qtw.api;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException {
//給文件中寫中文
writeCNText();
//讀取文件中的中文
readCNText();
}
//讀取中文
public static void readCNText() throws IOException {
FileInputStream fis = new FileInputStream("e:\\test\\a.txt");
int ch = 0;
while((ch = fis.read())!=-1){
System.out.println(ch);
}
}
//寫中文
public static void writeCNText() throws IOException {
FileOutputStream fos = new FileOutputStream("e:\\test\\a.txt");
fos.write("a北京歡迎你".getBytes());
fos.close();
}
}
??上面程序在讀取含有中文的文件時,我們并沒有看到具體的中文校辩,而是看到一些數(shù)字窘问,這是什么原因呢?既然看不到中文宜咒,那么我們?nèi)绾螌ζ渲械闹形淖鎏幚砟鼗莺眨恳鉀Q這個問題,我們必須研究下字符的編碼過程故黑。
2.2 字符輸入流Reader
??上述程序中我們讀取擁有中文的文件時儿咱,使用的字節(jié)流在讀取庭砍,那么我們讀取到的都是一個一個字節(jié)。只要把這些字節(jié)去查閱對應的編碼表混埠,就能夠得到與之對應的字符逗威。API中是否給我們已經(jīng)提供了讀取相應字符的功能流對象,Reader岔冀,讀取字符流的抽象超類凯旭。
read():讀取單個字符并返回
read(char[]):將數(shù)據(jù)讀取到數(shù)組中,并返回讀取的個數(shù)使套。
2.3.1 FileReader類
??查閱FileInputStream的API罐呼,發(fā)現(xiàn)FileInputStream 用于讀取諸如圖像數(shù)據(jù)之類的原始字節(jié)流。要讀取字符流侦高,請考慮使用 FileReader嫉柴。打開FileReader的API介紹。用來讀取字符文件的便捷類奉呛。此類的構(gòu)造方法假定默認字符編碼和默認字節(jié)緩沖區(qū)大小都是適當?shù)?/p>
構(gòu)造方法
2.2.2 FileReader讀取包含中文的文件
使用FileReader讀取包含中文的文件
package com.qtw.api;
import java.io.FileReader;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException {
//讀取文件中的中文
readCNText();
}
//讀取中文
public static void readCNText() throws IOException {
FileReader fr = new FileReader("e:\\test\\a.txt");
int ch = 0;
while((ch = fr.read())!=-1){
//輸出的字符對應的編碼值
System.out.println(ch);
//輸出字符本身
System.out.println((char)ch);
}
}
}
2.3 字符輸出流Writer
??既然有專門用于讀取字符的流對象计螺,那么肯定也有寫的字符流對象,查閱API瞧壮,發(fā)現(xiàn)有一個Writer類登馒,Writer是寫入字符流的抽象類。其中描述了相應的寫的動作咆槽。
2.3.1 FileWriter類
??查閱FileOutputStream的API陈轿,發(fā)現(xiàn)FileOutputStream 用于寫入諸如圖像數(shù)據(jù)之類的原始字節(jié)的流。要寫入字符流秦忿,請考慮使用 FileWriter麦射。打開FileWriter的API介紹。用來寫入字符文件的便捷類灯谣。此類的構(gòu)造方法假定默認字符編碼和默認字節(jié)緩沖區(qū)大小都是可接受的潜秋。
構(gòu)造方法
2.3.2 FileWriter寫入中文到文件中
寫入字符到文件中,先進行流的刷新胎许,再進行流的關閉峻呛。
package com.qtw.api;
import java.io.FileWriter;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException {
//演示FileWriter 用于操作文件的便捷類。
FileWriter fw = new FileWriter("e:\\test\\a.txt");
fw.write("你好謝謝再見");//這些文字都要先編碼呐萨。都寫入到了流的緩沖區(qū)中杀饵。
fw.flush();
fw.close();
}
}
2.4 flush()和close()的區(qū)別?
??flush():將流中的緩沖區(qū)緩沖的數(shù)據(jù)刷新到目的地中谬擦,刷新后切距,流還可以繼續(xù)使用。
??close():關閉資源惨远,但在關閉前會將緩沖區(qū)中的數(shù)據(jù)先刷新到目的地谜悟,否則丟失數(shù)據(jù)话肖,然后在關閉流。流不可以使用葡幸。如果寫入數(shù)據(jù)多最筒,一定要一邊寫一邊刷新,最后一次可以不刷新蔚叨,由close完成刷新并關閉床蜘。
2.5 字符流練習
2.5.1 復制文本文件
練習:復制文本文件。
思路:
- 既然是文本涉及編碼表蔑水。需要用字符流邢锯。
- 操作的是文件。涉及硬盤搀别。
- 有指定碼表嗎丹擎?沒有,默認就行歇父。
操作的是文件蒂培,使用的 默認碼表。使用哪個字符流對象榜苫。直接使用字符流操作文件的便捷類护戳。FileReader FileWriter
public class CopyTextFileTest {
public static void main(String[] args) throws IOException {
copyTextFile();
}
public static void copyTextFile() throws IOException {
//1,明確源和目的。
FileReader fr = new FileReader("c:\\cn.txt");
FileWriter fw = 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)讀寫操作羔飞。效率低。
int ch = 0;
while((ch=fr.read())!=-1){
fw.write(ch);
}
*/
//3,關閉資源檐春。
fw.close();
fr.close();
}
}