Java中字節(jié)流和字符流的理解(超精簡(jiǎn)!)
引言
在完完全全的完成本學(xué)期的學(xué)習(xí)任務(wù)之后,終于可以有時(shí)間繼續(xù)更新Java相關(guān)的文章了。那么今天我們要學(xué)習(xí)的是的Java中的IO流(I即為Input,O即為Output),也稱為輸入流,輸出流,其主要的作用是為了能夠?qū)ξ募械臄?shù)據(jù)進(jìn)行輸入和輸出(讀和寫),更加方便了今后我們?cè)贘ava道路上的學(xué)習(xí),好了,廢話不多說,我們開始今天的學(xué)習(xí)吧!
字節(jié)流和字符流
在上圖中,橙色部分是抽象類,而藍(lán)色部分則是實(shí)現(xiàn)類
字節(jié)流
字節(jié)流,顧名思義就是將數(shù)據(jù)細(xì)分為字節(jié)對(duì)文件進(jìn)行讀和寫的操作, 主要分為字節(jié)輸入流和字節(jié)輸出流。
字節(jié)輸入流
下面是字節(jié)輸入流中經(jīng)常會(huì)用到的構(gòu)造器和方法:
構(gòu)造器 | 說明 |
public FileInputStream(File file) | 創(chuàng)建字節(jié)輸入流管道與源文件對(duì)象接通 |
public FileInputStream(String pathname) | 創(chuàng)建字節(jié)輸入流管道與源文件路徑接通 |
方法名稱 | 說明 |
public int read() | 每次讀取一個(gè)字節(jié)返回,如果字節(jié)已經(jīng)沒有可讀的返回-1 |
public int read(byte[ ] buffer) | 每次讀取一個(gè)字節(jié)數(shù)組返回,如果字節(jié)已經(jīng)沒有可讀的返回-1 |
接下來通過代碼更好的加深對(duì)這一部分知識(shí)點(diǎn)的理解吧!
File file = new File("File//data.txt"); //第一種構(gòu)造器,參數(shù)是File類 InputStream inputStream = new FileInputStream(file); //第二種構(gòu)造器,參數(shù)是文件的路徑,可以是相對(duì)也可以是絕對(duì)的路徑 InputStream inputStream1 = new FileInputStream("File//data.txt"); //通過字節(jié)讀取文件中的數(shù)據(jù) int len; while ((len=inputStream.read()) != -1){ System.out.print((char) len); } System.out.println(); //通過字節(jié)數(shù)組讀取文件中的數(shù)據(jù) byte [] buffer = new byte[3]; while ((len=inputStream1.read(buffer))!=-1){ String s = new String(buffer,0,len); System.out.print(s); } //輸出結(jié)果: //ab1abab //ab1abab
現(xiàn)在我們看到的輸出結(jié)果和文件中的內(nèi)容是一一對(duì)應(yīng)的,那么它就一定是沒有問題的了嗎?其實(shí)并不是,只是還沒有遇到問題而已,首先我們應(yīng)該了解到的是,在utf-8中,字母和數(shù)字都是一個(gè)字節(jié),而中文是由三個(gè)字節(jié)組成的,那么當(dāng)我們的文件中出現(xiàn)漢字的時(shí)候,第一種方法就無法實(shí)現(xiàn)正常的讀取了,因?yàn)槊看味甲x取一個(gè)字節(jié)的原因會(huì)將漢字拆解,在輸出的時(shí)候形成亂碼的情況;而第二種則方法可以在特殊的情況下實(shí)現(xiàn)對(duì)漢字的輸出,必須滿足的條件是剛好中文的三個(gè)字節(jié)都在同一個(gè)字節(jié)數(shù)組中。
字節(jié)輸入流并不適合所有的文件數(shù)據(jù),由此而引出了字符輸入流。
字節(jié)輸出流
下面是字節(jié)輸出流常用到的方法:
方法 | 說明 |
public void write (int a) | 寫一個(gè)字節(jié)出去 |
public void write (byte [ ]buffer) | 寫一個(gè)字節(jié)數(shù)組出去 |
public void write (byte [ ]buffer,int off, int len) | 將一個(gè)字節(jié)數(shù)組中的一部分寫出去 |
file.close() | 流的關(guān)閉,不能再寫數(shù)據(jù) |
file.flush() | 流的更新,還可以繼續(xù)寫數(shù)據(jù) |
接下來通過代碼更好的加深對(duì)這一部分知識(shí)點(diǎn)的理解吧!
OutputStream outputStream = new FileOutputStream("File//data.txt",true); //true表示可以對(duì)文件進(jìn)行追加內(nèi)容,若沒有true則會(huì)在關(guān)閉文件之后,進(jìn)行寫文件的時(shí)候會(huì)對(duì)之前的內(nèi)容進(jìn)行覆蓋。 outputStream.write('a'); outputStream.write(13); outputStream.write('美'); outputStream.flush(); byte[] buffer = {'s','y','l','m',99}; outputStream.write(buffer); outputStream.write(buffer,1,3); outputStream.close();
經(jīng)過上面一系列操作以后,會(huì)將這些數(shù)據(jù)寫進(jìn)data.txt文件之中,但是仍然會(huì)出現(xiàn)問題,有時(shí)無法將中文正常的寫進(jìn)去,那么它也不是一個(gè)適合所有文件的,由此而引出了字符輸出流。
字符流
字符流,顧名思義就是將數(shù)據(jù)細(xì)分為字符對(duì)文件進(jìn)行讀和寫的操作, 主要分為字符輸入流和字符輸出流。
字符輸入流
下面是字符輸入流中經(jīng)常會(huì)用到的構(gòu)造器和方法:
構(gòu)造器 | 說明 |
public FileReader (File file) | 創(chuàng)建字符輸入流管道與源文件對(duì)象接通 |
public FileReader(String pathname) | 創(chuàng)建字符輸入流管道與源文件路徑接通 |
方法 | 說明 |
public int read() | 每次讀取一個(gè)字符返回,如果字符已經(jīng)沒有可讀的返回-1 |
public int read(char [ ]buffer) | 每次讀取一個(gè)字符數(shù)組返回,返回讀取的字符個(gè)數(shù),如果字符沒有可讀的返回-1 |
字符輸入流的構(gòu)造器和方法大致上和字節(jié)輸入流的相同,不同的地方在于字符輸入流是以字符為單位的讀取,無論你是字母還是數(shù)字,都作為一個(gè)字符進(jìn)行讀取,這樣便可以避免在讀取中文的時(shí)候出現(xiàn)亂碼的問題。
接下來通過一部分代碼來加深對(duì)它的理解吧!
File file = new File("File//data.txt"); //第一種構(gòu)造器,參數(shù)是File類 FileReader fileReader = new FileReader(file); //第二種構(gòu)造器,參數(shù)是文件的絕對(duì)路徑或者相對(duì)路徑 FileReader fileReader1 = new FileReader("File//data.txt"); //第一種方法,一個(gè)一個(gè)字符讀取 int len; while ((len = fileReader.read())!=-1){ System.out.print((char) len); } //第二種方法,以字符數(shù)組進(jìn)行讀取 char []buffer = new char[3]; while ((len = fileReader1.read(buffer))!=-1){ String s = new String(buffer,0,len); System.out.println(s); } //輸出結(jié)果: //110,119,120 //110 //,11 //9,1 //20
通過以字符為單位的讀寫,便可以避免在讀取中文的時(shí)候出現(xiàn)亂碼的問題了。
字符輸出流
下面是字符輸出流中經(jīng)常會(huì)用到的構(gòu)造器和方法:
構(gòu)造器 | 說明 |
public FileWriter(File file) | 創(chuàng)建字符輸出流管道與源文件對(duì)象接通 |
public FileWriter(File file,boolean append) | 創(chuàng)建字符輸出流管道與源文件對(duì)象接通,可追加數(shù)據(jù) |
public FileWriter(String filepath) | 創(chuàng)建字符輸出流管道與源文件路徑接通 |
public FileWriter(String filepath,boolean append) | 創(chuàng)建字符輸出流管道與源文件路徑接通,可追加 |
方法 | 說明 |
void writer(int c) | 寫入一個(gè)字符 |
void writer (char [ ] buffer) | 寫入一個(gè)字符數(shù)組 |
void writer (char[ ]buffer,int off,int len) | 寫入字符數(shù)組的一部分 |
void writer(String str) | 寫入一個(gè)字符串 |
void writer(String str,int off,int len) | 寫入字符串的一部分 |
close和flush | 輸出流的關(guān)閉和刷新 |
接下來就通過代碼來加深對(duì)它的理解吧!
FileWriter fileWriter = new FileWriter("File//data.txt"); fileWriter.write('k'); fileWriter.write('d'); char []buffer = {'i','r','v','i','n','g'}; fileWriter.write(buffer); fileWriter.flush(); String s = "James"; fileWriter.write(s); fileWriter.write(s,0,4); fileWriter.close();
字符輸出流的使用便可以很好地解決了中文不能正常寫入文件的問題了。
附:字節(jié)流和字符流的區(qū)別
字節(jié)流操作的基本單元為字節(jié);字符流操作的基本單元為Unicode碼元。
字節(jié)流默認(rèn)不使用緩沖區(qū);字符流使用緩沖區(qū)。
字節(jié)流在操作的時(shí)候本身是不會(huì)用到緩沖區(qū)的,是與文件本身直接操作的,所以字節(jié)流在操作文件時(shí),即使不關(guān)閉資源,文件也能輸出;字符流在操作的時(shí)候是使用到緩沖區(qū)的。如果字符流不調(diào)用close或flush方法,則不會(huì)輸出任何內(nèi)容。
字節(jié)流通常用于處理二進(jìn)制數(shù)據(jù),實(shí)際上它可以處理任意類型的數(shù)據(jù),但它不支持直接寫入或讀取Unicode碼元;字符流通常處理文本數(shù)據(jù),它支持寫入及讀取Unicode碼元。
字節(jié)流可用于任何類型的對(duì)象,包括二進(jìn)制對(duì)象,而字符流只能處理字符或者字符串; 字節(jié)流提供了處理任何類型的IO操作的功能,但它不能直接處理Unicode字符,而字符流就可以。
字節(jié)流和字符流的轉(zhuǎn)換
字節(jié)流是最基本的,所有的InputStream和OutputStream的子類都是,主要用在處理二進(jìn)制數(shù)據(jù),它是按字節(jié)來處理的,但實(shí)際中很多的數(shù)據(jù)是文本,又提出了字符流的概念,它是按虛擬機(jī)的encode來處理,也就是要進(jìn)行字符集的轉(zhuǎn)化,這兩個(gè)之間通過 InputStreamReader,OutputStreamWriter來關(guān)聯(lián),實(shí)際上是通過byte[]和String來關(guān)聯(lián)。在從字節(jié)流轉(zhuǎn)化為字符流時(shí),實(shí)際上就是byte[]轉(zhuǎn)化為String時(shí),而在字符流轉(zhuǎn)化為字節(jié)流時(shí),實(shí)際上是String轉(zhuǎn)化為byte[]時(shí)。
字符流處理的單元為2個(gè)字節(jié)的Unicode字符,分別操作字符、字符數(shù)組或字符串,而字節(jié)流處理單元為1個(gè)字節(jié),操作字節(jié)和字節(jié)數(shù)組。所以字符流是由Java虛擬機(jī)將字節(jié)轉(zhuǎn)化為2個(gè)字節(jié)的Unicode字符為單位的字符而成的,所以它對(duì)多國語言支持性比較好!如果是音頻文件、圖片、歌曲,就用字節(jié)流好點(diǎn),如果是關(guān)系到中文(文本)的,用字符流好點(diǎn)。所有文件的儲(chǔ)存是都是字節(jié)(byte)的儲(chǔ)存,在磁盤上保留的并不是文件的字符而是先把字符編碼成字節(jié),再儲(chǔ)存這些字節(jié)到磁盤。在讀取文件(特別是文本文件)時(shí),也是一個(gè)字節(jié)一個(gè)字節(jié)地讀取以形成字節(jié)序列。
字節(jié)流可用于任何類型的對(duì)象,包括二進(jìn)制對(duì)象,而字符流只能處理字符或者字符串; 字節(jié)流提供了處理任何類型的IO操作的功能,但它不能直接處理Unicode字符,而字符流就可以。
字節(jié)流與字符流主要的區(qū)別是他們的的處理方式。
總結(jié)
到此這篇關(guān)于Java中字節(jié)流和字符流的文章就介紹到這了,更多相關(guān)Java字節(jié)流和字符流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中@RestControllerAdvice注解的使用
這篇文章主要介紹了SpringBoot中@RestControllerAdvice注解的使用,@RestControllerAdvice主要用精簡(jiǎn)客戶端返回異常,它可以捕獲各種異常,需要的朋友可以參考下2024-01-01java統(tǒng)計(jì)字符串中重復(fù)字符出現(xiàn)次數(shù)的方法
這篇文章主要介紹了java統(tǒng)計(jì)字符串中重復(fù)字符出現(xiàn)次數(shù)的方法,涉及java針對(duì)字符串的遍歷與判斷相關(guān)操作技巧,需要的朋友可以參考下2016-08-08springboot+swagger2.10.5+mybatis-plus 入門詳解
這篇文章主要介紹了springboot+swagger2.10.5+mybatis-plus 入門,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Mybatis基礎(chǔ)概念與高級(jí)應(yīng)用小結(jié)
這篇文章主要介紹了Mybatis基礎(chǔ)回顧與高級(jí)應(yīng)用,本文內(nèi)容有點(diǎn)小長,希望大家耐心閱讀,此文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06Java中使用Closeable接口自動(dòng)關(guān)閉資源詳解
這篇文章主要介紹了Java中使用Closeable接口自動(dòng)關(guān)閉資源詳解,Closeable接口繼承于AutoCloseable,主要的作用就是自動(dòng)的關(guān)閉資源,其中close()方法是關(guān)閉流并且釋放與其相關(guān)的任何方法,如果流已被關(guān)閉,那么調(diào)用此方法沒有效果,需要的朋友可以參考下2023-12-12使用maven的profile構(gòu)建不同環(huán)境配置的方法
這篇文章主要介紹了使用maven的profile構(gòu)建不同環(huán)境配置的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01