Java之IO操作总结
所謂IO,也就是Input與Output的縮寫(xiě)。在java中,IO涉及的范圍比較大,這里主要討論針對(duì)文件內(nèi)容的讀寫(xiě)
其他知識(shí)點(diǎn)將放置后續(xù)章節(jié)
對(duì)于文件內(nèi)容的操作主要分為兩大類
分別是:
- 字符流
- 字節(jié)流
其中,字符流有兩個(gè)抽象類:Writer Reader
其對(duì)應(yīng)子類FileWriter和FileReader可實(shí)現(xiàn)文件的讀寫(xiě)操作
BufferedWriter和BufferedReader能夠提供緩沖區(qū)功能,用以提高效率
同樣,字節(jié)流也有兩個(gè)抽象類:InputStream OutputStream
其對(duì)應(yīng)子類有FileInputStream和FileOutputStream實(shí)現(xiàn)文件讀寫(xiě)
BufferedInputStream和BufferedOutputStream提供緩沖區(qū)功能
概念:
字符流處理的單元為2個(gè)字節(jié)的Unicode字符,分別操作字符、字符數(shù)組或字符串,而字節(jié)流處理單元為1個(gè)字節(jié), 操作字節(jié)和字節(jié)數(shù)組。所以字符流是由Java虛擬機(jī)將字節(jié)轉(zhuǎn)化為2個(gè)字節(jié)的Unicode字符為單位的字符而成的,所以它對(duì)多國(guó)語(yǔ)言支持性比較好!如果是 音頻文件、圖片、歌曲,就用字節(jié)流好點(diǎn),如果是關(guān)系到中文(文本)的,用字符流好點(diǎn).
字節(jié)流可用于任何類型的對(duì)象,包括二進(jìn)制對(duì)象,而字符流只能處理字符或者字符串; 2. 字節(jié)流提供了處理任何類型的IO操作的功能,但它不能直接處理Unicode字符,而字符流就可以。
轉(zhuǎn)換:
在從字節(jié)流轉(zhuǎn)化為字符流時(shí),實(shí)際上就是byte[]轉(zhuǎn)化為String時(shí),
public String(byte bytes[], String charsetName)
有一個(gè)關(guān)鍵的參數(shù)字符集編碼,通常我們都省略了,那系統(tǒng)就用操作系統(tǒng)的lang
而在字符流轉(zhuǎn)化為字節(jié)流時(shí),實(shí)際上是String轉(zhuǎn)化為byte[]時(shí),
byte[] String.getBytes(String charsetName)
也是一樣的道理
參考鏈接
字節(jié)流與字符流的區(qū)別 - hintcnuie - ITeye技術(shù)網(wǎng)站
俺當(dāng)初學(xué)IO的時(shí)候犯了不少迷糊,網(wǎng)上有些代碼也無(wú)法通過(guò)編譯,甚至風(fēng)格都很大不同,所以新手請(qǐng)注意:
1.本文代碼較長(zhǎng),不該省略的都沒(méi)省略,主要是因?yàn)樽鳛橐粋€(gè)新手需要養(yǎng)成良好的代碼編寫(xiě)習(xí)慣
2.本文在linux下編譯,類似于File.pathSeparator和File.separator這種表示方法是出于跨平臺(tái)性和健壯性考慮
3.代碼中有些操作有多種執(zhí)行方式,我采用了方式1…方式2…的表述,只需輕輕解開(kāi)注釋便可編譯
4.代碼中并沒(méi)有在主方法上拋出異常,而是分別捕捉,造成代碼過(guò)長(zhǎng),如果僅是測(cè)試,或者不想有好的編程習(xí)慣,那你就隨便拋吧……
5.功能類似的地方就沒(méi)有重復(fù)寫(xiě)注釋了,如果新手看不懂下面的代碼,那肯定是上面的沒(méi)有理解清楚
字符流
實(shí)例1:字符流的寫(xiě)入
import java.io.File;import java.io.FileWriter;import java.io.IOException;public class Demo {public static void main(String[] args ) {//創(chuàng)建要操作的文件路徑和名稱//其中,File.separator表示系統(tǒng)相關(guān)的分隔符,Linux下為:/ Windows下為:\\String path = File.separator + "home" + File.separator + "siu" + File.separator + "work" + File.separator + "demo.txt";//由于IO操作會(huì)拋出異常,因此在try語(yǔ)句塊的外部定義FileWriter的引用FileWriter w = null;try {//以path為路徑創(chuàng)建一個(gè)新的FileWriter對(duì)象//如果需要追加數(shù)據(jù),而不是覆蓋,則使用FileWriter(path,true)構(gòu)造方法w = new FileWriter(path);//將字符串寫(xiě)入到流中,\r\n表示換行想有好的w.write("Nerxious is a good boy\r\n");//如果想馬上看到寫(xiě)入效果,則需要調(diào)用w.flush()方法w.flush();} catch (IOException e) {e.printStackTrace();} finally {//如果前面發(fā)生異常,那么是無(wú)法產(chǎn)生w對(duì)象的 //因此要做出判斷,以免發(fā)生空指針異常if(w != null) {try {//關(guān)閉流資源,需要再次捕捉異常w.close();} catch (IOException e) {e.printStackTrace();}}}}}實(shí)例2:字符流的讀取
import java.io.File;import java.io.FileReader;import java.io.IOException;public class Demo2 {public static void main(String[] args ) {String path = File.separator + "home" + File.separator + "siu" + File.separator + "work" + File.separator + "demo.txt";FileReader r = null;try {r = new FileReader(path);//方式一:讀取單個(gè)字符的方式//每讀取一次,向下移動(dòng)一個(gè)字符單位int temp1 = r.read();System.out.println((char)temp1);int temp2 = r.read();System.out.println((char)temp2);//方式二:循環(huán)讀取//read()方法讀到文件末尾會(huì)返回-1/*while (true) {int temp = r.read();if (temp == -1) {break;}System.out.print((char)temp);}*///方式三:循環(huán)讀取的簡(jiǎn)化操作//單個(gè)字符讀取,當(dāng)temp不等于-1的時(shí)候打印字符/*int temp = 0;while ((temp = r.read()) != -1) {System.out.print((char)temp);}*///方式四:讀入到字符數(shù)組/*char[] buf = new char[1024];int temp = r.read(buf);//將數(shù)組轉(zhuǎn)化為字符串打印,后面參數(shù)的意思是//如果字符數(shù)組未滿,轉(zhuǎn)化成字符串打印后尾部也許會(huì)出現(xiàn)其他字符//因此,讀取的字符有多少個(gè),就轉(zhuǎn)化多少為字符串System.out.println(new String(buf,0,temp));*///方式五:讀入到字符數(shù)組的優(yōu)化//由于有時(shí)候文件太大,無(wú)法確定需要定義的數(shù)組大小//因此一般定義數(shù)組長(zhǎng)度為1024,采用循環(huán)的方式讀入/*char[] buf = new char[1024];int temp = 0;while((temp = r.read(buf)) != -1) {System.out.print(new String(buf,0,temp));}*/} catch (IOException e) {e.printStackTrace();} finally {if(r != null) {try {r.close();} catch (IOException e) {e.printStackTrace();}}}}}實(shí)例3:文本文件的復(fù)制
import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Demo {public static void main(String[] args ) {String doc = File.separator + "home" + File.separator + "siu" + File.separator + "work" + File.separator + "demo.txt";String copy = File.separator + "home" + File.separator + "siu" + File.separator + "life" + File.separator + "lrc.txt";FileReader r = null;FileWriter w = null;try {r = new FileReader(doc);w = new FileWriter(copy);//方式一:單個(gè)字符寫(xiě)入int temp = 0;while((temp = r.read()) != -1) {w.write(temp);}//方式二:字符數(shù)組方式寫(xiě)入/*char[] buf = new char[1024];int temp = 0;while ((temp = r.read(buf)) != -1) {w.write(new String(buf,0,temp));}*/} catch (IOException e) {e.printStackTrace();} finally {//分別判斷是否空指針引用,然后關(guān)閉流if(r != null) {try {r.close();} catch (IOException e) {e.printStackTrace();}}if(w != null) {try {w.close();} catch (IOException e) {e.printStackTrace();}}}}}實(shí)例4:利用字符流的緩沖區(qū)來(lái)進(jìn)行文本文件的復(fù)制
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Demo {public static void main(String[] args ) {String doc = File.separator + "home" + File.separator + "siu" + File.separator + "work" + File.separator + "demo.txt";String copy = File.separator + "home" + File.separator + "siu" + File.separator + "life" + File.separator + "lrc.txt";FileReader r = null;FileWriter w = null;//創(chuàng)建緩沖區(qū)的引用BufferedReader br = null;BufferedWriter bw = null;try {r = new FileReader(doc);w = new FileWriter(copy);//創(chuàng)建緩沖區(qū)對(duì)象//將需要提高效率的FileReader和FileWriter對(duì)象放入其構(gòu)造函數(shù)內(nèi)//當(dāng)然,也可以使用匿名對(duì)象的方式 br = new BufferedReader(new FileReader(doc));br = new BufferedReader(r);bw = new BufferedWriter(w);String line = null;//讀取行,直到返回null//readLine()方法只返回?fù)Q行符之前的數(shù)據(jù)while((line = br.readLine()) != null) {//使用BufferWriter對(duì)象的寫(xiě)入方法bw.write(line);//寫(xiě)完文件內(nèi)容之后換行//newLine()方法依據(jù)平臺(tái)而定//windows下的換行是\r\n//Linux下則是\nbw.newLine();} } catch (IOException e) {e.printStackTrace();} finally {//此處不再需要捕捉FileReader和FileWriter對(duì)象的異常//關(guān)閉緩沖區(qū)就是關(guān)閉緩沖區(qū)中的流對(duì)象if(br != null) {try {r.close();} catch (IOException e) {e.printStackTrace();}}if(bw != null) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}}}}字節(jié)流
實(shí)例5:字節(jié)流的寫(xiě)入
import java.io.File;import java.io.FileOutputStream;import java.io.IOException;public class Demo {public static void main(String[] args ) {String path = File.separator + "home" + File.separator + "siu" +File.separator + "work" + File.separator + "demo.txt";FileOutputStream o = null;try {o = new FileOutputStream(path);String str = "Nerxious is a good boy\r\n";byte[] buf = str.getBytes();//也可以直接使用o.write("String".getBytes());//因?yàn)樽址褪且粋€(gè)對(duì)象,能直接調(diào)用方法o.write(buf);} catch (IOException e) {e.printStackTrace();} finally {if(o != null) {try {o.close();} catch (IOException e) {e.printStackTrace();}}}}}實(shí)例6:字節(jié)流的讀取
import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class Demo {public static void main(String[] args ) {String path = File.separator + "home" + File.separator + "siu" +File.separator + "work" + File.separator + "demo.txt";FileInputStream i = null;try {i = new FileInputStream(path);//方式一:單個(gè)字符讀取//需要注意的是,此處我用英文文本測(cè)試效果良好//但中文就悲劇了,不過(guò)下面兩個(gè)方法效果良好int ch = 0;while((ch=i.read()) != -1){System.out.print((char)ch);}//方式二:數(shù)組循環(huán)讀取/*byte[] buf = new byte[1024];int len = 0;while((len = i.read(buf)) != -1) {System.out.println(new String(buf,0,len));}*///方式三:標(biāo)準(zhǔn)大小的數(shù)組讀取/*//定一個(gè)一個(gè)剛好大小的數(shù)組//available()方法返回文件的字節(jié)數(shù)//但是,如果文件過(guò)大,內(nèi)存溢出,那就悲劇了//所以,親們要慎用!!!上面那個(gè)方法就不錯(cuò)byte[] buf = new byte[i.available()];i.read(buf);//因?yàn)閿?shù)組大小剛好,所以轉(zhuǎn)換為字符串時(shí)無(wú)需在構(gòu)造函數(shù)中設(shè)置起始點(diǎn)System.out.println(new String(buf));*/} catch (IOException e) {e.printStackTrace();} finally {if(i != null) {try {i.close();} catch (IOException e) {e.printStackTrace();}}}}}實(shí)例7:二進(jìn)制文件的復(fù)制
import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class Demo {public static void main(String[] args ) {String bin = File.separator + "home" + File.separator + "siu" +File.separator + "work" + File.separator + "一個(gè)人生活.mp3";String copy = File.separator + "home" + File.separator + "siu" +File.separator + "life" + File.separator + "一個(gè)人生活.mp3";FileInputStream i = null;FileOutputStream o = null;try {i = new FileInputStream(bin);o = new FileOutputStream(copy);//循環(huán)的方式讀入寫(xiě)出文件,從而完成復(fù)制byte[] buf = new byte[1024];int temp = 0;while((temp = i.read(buf)) != -1) {o.write(buf, 0, temp);}} catch (IOException e) {e.printStackTrace();} finally {if(i != null) {try {i.close();} catch (IOException e) {e.printStackTrace();}}if(o != null) {try {o.close();} catch (IOException e) {e.printStackTrace();}}}}}實(shí)例8:利用字節(jié)流的緩沖區(qū)進(jìn)行二進(jìn)制文件的復(fù)制
import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class Demo {public static void main(String[] args ) {String bin = File.separator + "home" + File.separator + "siu" +File.separator + "work" + File.separator + "一個(gè)人生活.mp3";String copy = File.separator + "home" + File.separator + "siu" +File.separator + "life" + File.separator + "一個(gè)人生活.mp3";FileInputStream i = null;FileOutputStream o = null;BufferedInputStream bi = null;BufferedOutputStream bo = null;try {i = new FileInputStream(bin);o = new FileOutputStream(copy);bi = new BufferedInputStream(i);bo = new BufferedOutputStream(o);byte[] buf = new byte[1024];int temp = 0;while((temp = bi.read(buf)) != -1) {bo.write(buf,0,temp);}} catch (IOException e) {e.printStackTrace();} finally {if(bi != null) {try {i.close();} catch (IOException e) {e.printStackTrace();}}if(bo != null) {try {o.close();} catch (IOException e) {e.printStackTrace();}}}}}初學(xué)者在學(xué)會(huì)使用字符流和字節(jié)流之后未免會(huì)產(chǎn)生疑問(wèn):什么時(shí)候該使用字符流,什么時(shí)候又該使用字節(jié)流呢?
其實(shí)仔細(xì)想想就應(yīng)該知道,所謂字符流,肯定是用于操作類似文本文件或者帶有字符文件的場(chǎng)合比較多
而字節(jié)流則是操作那些無(wú)法直接獲取文本信息的二進(jìn)制文件,比如圖片,mp3,視頻文件等
說(shuō)白了在硬盤(pán)上都是以字節(jié)存儲(chǔ)的,只不過(guò)字符流在操作文本上面更方便一點(diǎn)而已
此外,為什么要利用緩沖區(qū)呢?
我們知道,像迅雷等下載軟件都有個(gè)緩存的功能,硬盤(pán)本身也有緩沖區(qū)
試想一下,如果一有數(shù)據(jù),不論大小就開(kāi)始讀寫(xiě),勢(shì)必會(huì)給硬盤(pán)造成很大負(fù)擔(dān),它會(huì)感覺(jué)很不爽
人不也一樣,一頓飯不讓你一次吃完,每分鐘喂一勺,你怎么想?
因此,采用緩沖區(qū)能夠在讀寫(xiě)大文件的時(shí)候有效提高效率
最后解決的一個(gè)問(wèn)題是字節(jié)流和字符流的轉(zhuǎn)化,使用的是InputStreamReader和OutputStreamWriter,它們本身屬于的是reader和writer字符流,我們之所以會(huì)用到這些轉(zhuǎn)化流是因?yàn)橄到y(tǒng)有時(shí)候只給我們提供了字節(jié)流,為了方便操作,要用到字符流。比如說(shuō)System.in標(biāo)準(zhǔn)輸入流就是字節(jié)流。你想從那里得到用戶在鍵盤(pán)上的輸入,只能是以轉(zhuǎn)換流將它轉(zhuǎn)換為Reader以方便自己的程序讀取輸入。再比如說(shuō)Socket里的getInputStream()很明顯只給你提供字節(jié)流,你要想讀取字符,就得給他套個(gè)InputStreamReader()用來(lái)讀取。
package com.zaojiahua.iodemo;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter;public class Test {public static void main(String[] args) throws IOException {//字節(jié)流和字符流的相互轉(zhuǎn)化FileInputStream fileInputStream = new FileInputStream("input.txt");//inputSreamReader本來(lái)就是reader對(duì)象,創(chuàng)建的時(shí)候需要傳入一個(gè)InputStream對(duì)象,將字節(jié)流轉(zhuǎn)化為字符流BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));//將字符流轉(zhuǎn)化為字節(jié)流OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("output.txt"));BufferedWriter writer = new BufferedWriter(outputStreamWriter);//實(shí)現(xiàn)拷貝文件的操作String buf;while((buf = reader.readLine()) != null){writer.write(buf);writer.newLine();System.out.println(buf);}//關(guān)閉流reader.close();writer.close();} }參考鏈接
java中的IO操作總結(jié)(一) - Nerxious - 博客園
java中的IO操作|皂莢花
Java之美[從菜鳥(niǎo)到高手演變]之Java中的IO - 智慧演繹,無(wú)處不在 - 博客頻道 - CSDN.NET
總結(jié)
以上是生活随笔為你收集整理的Java之IO操作总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用C与C++混合编程封装UDP协议
- 下一篇: 《爬虫写得好,铁窗关到老》教你把握爬虫的