IO流常用基類
字節(jié)流的抽象基類:
InputStream
OutputStream
字符流的抽象基類:
Reader
Writer
注意:由這四個(gè)類派生出來的子類名稱都是以其父類名作為子類名的后綴的。例如穆咐,InputStream的子類——FileInputStream元扔,Reader的子類——FileReader。
字節(jié)流
字節(jié)流的基本操作與字符流類同派阱,但它不僅可以操作字符株扛,還可以操作其他媒體文件护姆。這里,我列出比較常用的字節(jié)流先较,如下:
FileInputStream
FileOutputStream
BufferedInputStream
BufferedOutputStream
字節(jié)輸出流——FileOutputStream
首先我為讀者介紹一下字節(jié)輸出流——FileOutputStream携冤。以一個(gè)例子來作為我的開場(chǎng)白。
例闲勺,向一個(gè)文本文件中寫入數(shù)據(jù)曾棕。
這里我使用字節(jié)輸出流——FileOutputStream向一個(gè)文本文件中寫入數(shù)據(jù),此處直接給出示例代碼菜循。
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
/*
* 將數(shù)據(jù)寫入到文件中翘地。
* 使用字節(jié)輸出流。
* FileOutputStream癌幕。
*/
File dir = new File("tempfile");
if (!dir.exists()) {
dir.mkdir();
}
// 1衙耕、創(chuàng)建字節(jié)輸出流對(duì)象,用于操作文件勺远,在對(duì)象初始化時(shí)必須明確數(shù)據(jù)存儲(chǔ)的目的地橙喘。
// 輸出流所關(guān)聯(lián)的目的地,如果不存在胶逢,會(huì)自動(dòng)創(chuàng)建厅瞎。如果存在饰潜,則覆蓋。
FileOutputStream fos = new FileOutputStream("tempfile\\fos.txt");
// 2和簸、調(diào)用輸出流的寫功能彭雾。
// String str = "abcde";
// byte[] buf = str.getBytes();
fos.write("abcde".getBytes());
// 3、釋放資源锁保。
fos.close();
}
}
這里我們須注意一點(diǎn)——?jiǎng)?chuàng)建字節(jié)輸出流對(duì)象用于操作文件冠跷,在對(duì)象初始化時(shí)必須明確數(shù)據(jù)存儲(chǔ)的目的地,輸出流所關(guān)聯(lián)的目的地身诺,如果不存在,則會(huì)自動(dòng)創(chuàng)建抄囚;如果存在霉赡,則會(huì)覆蓋。
對(duì)IOException的處理方式
在使用字節(jié)輸出流——FileOutputStream向一個(gè)文本文件中寫入數(shù)據(jù)時(shí)幔托,就不可避免地發(fā)生IOException異常穴亏,對(duì)該異常的正確處理方式究竟是怎樣的呢?下面已給出重挑。
public class IOExceptionDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("tempfile\\fos.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
// 自處理.... 但通常將異常信息寫入到日志文件中以進(jìn)行記錄嗓化。
System.out.println(e.toString() + "----------------");
} finally {
if (fos != null) // 放在try代碼塊里面亦可
try {
fos.close();
} catch (IOException e) {
// 一般可以throw RuntimeException異常,或者將異常信息寫入到日志文件中以進(jìn)行記錄谬哀。
throw new RuntimeException("關(guān)閉失敗" + e);
}
}
}
}
注意:最后無論如何都應(yīng)關(guān)閉資源刺覆,所以應(yīng)放在finally代碼塊中。以后在對(duì)IO流的操作中史煎,出現(xiàn)IOException異常谦屑,就按照上述代碼進(jìn)行處理。
字節(jié)輸出流的續(xù)寫和換行
現(xiàn)在思考這樣一個(gè)問題:如果想在原有文件上繼續(xù)加入新的數(shù)據(jù)篇梭,咋整呢氢橙?很簡(jiǎn)單,創(chuàng)建一個(gè)FileOutputStream對(duì)象時(shí)恬偷,傳遞一個(gè)true參數(shù)悍手,代表不覆蓋已有的文件,即在已有文件的末尾處進(jìn)行數(shù)據(jù)續(xù)寫袍患。示例代碼如下:
public class IOExceptionDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("tempfile\\fos.txt", true); // 傳入true實(shí)現(xiàn)續(xù)寫坦康。
String str = LINE_SEPARATOR + "hello";
fos.write(str.getBytes());
} catch (IOException e) {
// 自處理....
System.out.println(e.toString() + "----------------");
} finally {
if (fos != null)
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("關(guān)閉失敗" + e);
}
}
}
}
注意:\r\n在Windows中表示行終止符,但在其他系統(tǒng)中并不是這樣协怒,所以為了更加通用涝焙,使用System類的getProperty(“l(fā)ine.separator”)方法得到系統(tǒng)的行終止符。
字節(jié)輸入流——FileInputStream
我們知道如何使用字節(jié)輸出流——FileOutputStream向一個(gè)文本文件中寫入數(shù)據(jù)之后孕暇,就要考慮將已有文件的數(shù)據(jù)讀取出來仑撞。
現(xiàn)在就有這樣一個(gè)需求:從硬盤的一個(gè)文件中讀取內(nèi)容赤兴。
分析:既然是讀取文件,顯然要使用InputStream隧哮,而且又因?yàn)槭且僮魑募傲迹宰罱K應(yīng)使用FileInputStream。使用字節(jié)輸入流——FileInputStream讀取文件有三種方式沮翔,下面我會(huì)詳述這三種方式陨帆。
首先使用第一種方式來讀取文件,給出示例代碼如下采蚀,以供讀者參考疲牵。
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
// 為了確保文件一定在讀之前是存在的,將字符串路徑封裝成File對(duì)象榆鼠。
File file = new File("tempfile\\fos.txt");
if (!(file.exists())) {
throw new RuntimeException("要讀取的文件不存在");
}
// 創(chuàng)建文件字節(jié)讀取流對(duì)象時(shí)纲爸,必須明確與之關(guān)聯(lián)的數(shù)據(jù)源。
FileInputStream fis = new FileInputStream(file);
// 調(diào)用讀取流對(duì)象的讀方法妆够。read();
int by = 0;
while ((by = fis.read()) != -1) {
System.out.println(by);
}
// 關(guān)閉資源
fis.close();
}
}
我覺得總有初學(xué)者對(duì)以上程序代碼感到一頭霧水的识啦,但是沒關(guān)系啦!下面我就會(huì)畫一張圖來解釋其原理神妹,圖畫的糙颓哮,還請(qǐng)讀者諒解。
這里寫圖片描述
接下來就使用第二種方式來讀取文件鸵荠,同樣給出示例代碼如下(其中加入了對(duì)IOException異常的處理)冕茅,以供讀者參考。
public class FileInputStreamDemo2 {
private static final int DEFAULT_SIZE = 1024; // 緩沖區(qū)大小可以是1024的整數(shù)倍蛹找。
public static void main(String[] args) {
// 演示第二種讀取方式嵌赠,read(byte[]);
FileInputStream fis = null;
try {
fis = new FileInputStream("tempfile\\fos.txt");
// 創(chuàng)建一個(gè)字節(jié)數(shù)組。
byte[] buf = new byte[DEFAULT_SIZE];
int len = 0;
// 調(diào)用read(byte[])方法
while ((len = fis.read(buf)) != -1) { // len記錄的是往字節(jié)數(shù)組里存儲(chǔ)的字節(jié)個(gè)數(shù)熄赡。
System.out.println(new String(buf, 0, len)); // 將字節(jié)數(shù)組轉(zhuǎn)成字符串姜挺,打印并看一下效果。
}
} catch (IOException e) {
// 將異常信息寫入到日志文件中以進(jìn)行記錄彼硫。
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
// 一般可以throw RuntimeException異常炊豪,或者將異常信息寫入到日志文件中以進(jìn)行記錄。
e.printStackTrace();
}
}
}
}
}
從以上程序代碼中拧篮,可知在創(chuàng)建緩沖區(qū)(一個(gè)字節(jié)數(shù)組)時(shí)词渤,緩沖區(qū)的大小一般設(shè)置為1024的整數(shù)倍。同上串绩,下面我畫一張糙圖來解釋上述程序代碼缺虐。
這里寫圖片描述
最后,使用第三種方式來讀取文件礁凡,給出示例代碼如下高氮,供讀者參考慧妄。
public class FileInputStreamDemo3 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("tempfile\\fos.txt");
System.out.println(fis.available()); // 獲取與之關(guān)聯(lián)的文件的字節(jié)數(shù)。
byte[] buf = new byte[fis.available()]; // 定義一個(gè)剛剛好的緩沖區(qū)剪芍,不用再循環(huán)了塞淹。不過慎用!W锕饱普!
fis.read(buf);
String s = new String(buf);
System.out.println(s);
fis.close();
}
}
注意:不建議使用這種方式,因?yàn)榭赡軙?huì)有內(nèi)存溢出異常状共。
復(fù)制文本文件
現(xiàn)在有這樣一個(gè)需求:復(fù)制一個(gè)文本文件套耕。為了解決這個(gè)需求,首先就要分析一下破題思路峡继,復(fù)制文本文件說到底就是一個(gè)讀取源數(shù)據(jù)箍铲,并將數(shù)據(jù)寫到目的地的過程,由于要操作設(shè)備上的數(shù)據(jù)鬓椭,所以需要用到流,讀用到了輸入流关划,寫用到了輸出流小染,而且操作的還是文本文件,最終就需要用到字節(jié)流中操作文件的流對(duì)象了贮折。解決該需求其實(shí)有兩種方式裤翩,下面我會(huì)一一詳述這兩種方式。
首先使用第一種復(fù)制方式调榄,即從源數(shù)據(jù)中讀一個(gè)字節(jié)踊赠,就往目的地寫一個(gè)字節(jié)。下面給出示例代碼每庆,供讀者參考筐带。
public class CopyTextTest {
public static void main(String[] args) throws IOException {
copyText();
}
public static void copyText() throws IOException {
// 1、創(chuàng)建一個(gè)輸入流和源數(shù)據(jù)相關(guān)聯(lián)缤灵。
FileInputStream fis = new FileInputStream("IO流.txt");
// 2伦籍、創(chuàng)建一個(gè)輸出流,并通過輸出流創(chuàng)建一個(gè)目的地腮出。
FileOutputStream fos = new FileOutputStream("tempfile\\io_copy.txt");
// 3帖鸦、讀一個(gè),寫一個(gè)胚嘲。
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
fos.close();
fis.close();
}
}
接著再來看第二種復(fù)制方式作儿,同樣給出示例代碼如下。
public class CopyTextByBufTest {
public static void main(String[] args) {
copyTextByBuf();
}
public static void copyTextByBuf() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("IO流.txt");
fos = new FileOutputStream("tempfile\\io_buf_copy.txt");
// 創(chuàng)建一個(gè)緩沖區(qū)
byte[] buf = new byte[1024];
// 定義記錄個(gè)數(shù)的變量
int len = 0;
// 循環(huán)讀寫
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} catch (IOException e) {
// 異常日志馋劈。
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// 異常日志攻锰。
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
// 異常日志晾嘶。
e.printStackTrace();
}
}
}
}
}
相比第一種復(fù)制方式,此方式的復(fù)制效率會(huì)更高口注,所以建議使用第二種復(fù)制方式变擒。
字節(jié)流的緩沖區(qū)對(duì)象
現(xiàn)在有這樣一個(gè)需求:復(fù)制一個(gè)圖片。其解決思路如下:
用字節(jié)讀取流對(duì)象和圖片關(guān)聯(lián)寝志。
用字節(jié)寫入流對(duì)象創(chuàng)建一個(gè)圖片文件娇斑,用于存儲(chǔ)獲取到的圖片數(shù)據(jù)。
通過循環(huán)讀寫材部,完成數(shù)據(jù)的存儲(chǔ)毫缆。
關(guān)閉資源。
通過以上思路乐导,不難寫出如下代碼苦丁,程序代碼與復(fù)制一個(gè)文本文件非常相似。
import java.io.*;
class CopyPic {
public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream("c:\\2.jpg");
fis = new FileInputStream("c:\\1.jpg");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} catch(IOException e) {
throw new RuntimeException("復(fù)制文件失敗");
} finally {
try {
if(fis != null)
fis.close();
} catch(IOException e) {
throw new RuntimeException("讀取關(guān)閉失敗");
}
try {
if(fos != null)
fos.close();
} catch(IOException e) {
throw new RuntimeException("寫入關(guān)閉失敗");
}
}
}
}
我覺得總有初學(xué)者對(duì)以上程序代碼感到一頭霧水的物臂,但是沒關(guān)系啦旺拉!下面我就會(huì)畫一張圖來解釋其原理,圖畫的糙棵磷,還請(qǐng)讀者諒解蛾狗。
這里寫圖片描述
復(fù)制一個(gè)圖片的需求解決完之后,接下來就要引出字節(jié)流的緩沖區(qū)對(duì)象了仪媒,它們分別是BufferedOutputStream和BufferedInputStream沉桌,它倆是怎樣使用的呢?下面同樣以復(fù)制一個(gè)圖片的案例來看看字節(jié)流的緩沖區(qū)對(duì)象到底是如何應(yīng)用在代碼中的算吩。
public class CopyPicByBufferDemo {
public static void main(String[] args) throws IOException {
copyPicByBuffer();
}
public static void copyPicByBuffer() throws IOException {
// 演示緩沖區(qū)留凭。
// 1,創(chuàng)建具體的流對(duì)象偎巢。
FileInputStream fis = new FileInputStream("tempfile\\1.jpg");
// 對(duì)流進(jìn)行緩沖蔼夜。
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("tempfile\\copy_1.jpg");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
byte[] buf = new byte[1024];
int len = 0;
while ((len = bufis.read(buf)) != -1) { // 緩沖區(qū)的讀方法,從緩沖區(qū)里面讀出來的數(shù)據(jù)
bufos.write(buf, 0, len); // 緩沖區(qū)的寫方法压昼,向緩沖區(qū)里面寫數(shù)據(jù)挎扰。
bufos.flush(); // 刷新可有可無,因?yàn)榫彌_區(qū)滿了之后會(huì)自動(dòng)刷新巢音。
}
fos.close();
fis.close();
}
}
轉(zhuǎn)載地址:https://blog.csdn.net/yerenyuan_pku/article/details/78231697