一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語(yǔ)言|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Java基礎(chǔ)教程之字符流文件讀寫(xiě)

Java基礎(chǔ)教程之字符流文件讀寫(xiě)

2021-05-13 11:19Single_Yam Java教程

這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之字符流文件讀寫(xiě)的相關(guān)資料,,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

上篇文章,我們介紹了 java 的文件字節(jié)流框架中的相關(guān)內(nèi)容,而我們本篇文章將著重于文件字符流的相關(guān)內(nèi)容。

首先需要明確一點(diǎn)的是,字節(jié)流處理文件的時(shí)候是基于字節(jié)的,而字符流處理文件則是基于一個(gè)個(gè)字符為基本單元的。

但實(shí)際上,字符流操作的本質(zhì)就是「字節(jié)流操作」+「編碼」兩個(gè)過(guò)程的封裝,你想是不是,無(wú)論你是寫(xiě)一個(gè)字符到文件,你需要將字符編碼成二進(jìn)制,然后以字節(jié)為基本單位寫(xiě)入文件,或是你讀一個(gè)字符到內(nèi)存,你需要以字節(jié)為基本單位讀出,然后轉(zhuǎn)碼成字符。

理解這一點(diǎn)很重要,這將決定你對(duì)字符流整體上的理解是怎樣的,下面我們一起看看相關(guān) api 的設(shè)計(jì)。

基類 reader/writer

在正式學(xué)習(xí)字符流基類之前,我們需要知道 java 中是如何表示一個(gè)字符的。

首先,java 中的默認(rèn)字符編碼為:utf-8,而我們知道 utf-8 編碼的字符使用 1 到 4 個(gè)字節(jié)進(jìn)行存儲(chǔ),越常用的字符使用越少的字節(jié)數(shù)。

而 char 類型被定義為兩個(gè)字節(jié)大小,也就是說(shuō),對(duì)于通常的字符來(lái)說(shuō),一個(gè) char 即可存儲(chǔ)一個(gè)字符,但對(duì)于一些增補(bǔ)字符集來(lái)說(shuō),往往會(huì)使用兩個(gè) char 來(lái)表示一個(gè)字符。

reader 作為讀字符流的基類,它提供了最基本的字符讀取操作,我們一起看看。

先看看它的構(gòu)造器:

?
1
2
3
4
5
6
7
8
9
10
11
protected object lock;
protected reader() {
 this.lock = this;
}
 
protected reader(object lock) {
 if (lock == null) {
 throw new nullpointerexception();
 }
 this.lock = lock;
}

reader 是一個(gè)抽象類,所以毋庸置疑的是,這些構(gòu)造器是給子類調(diào)用的,用于初始化 lock 鎖對(duì)象,這一點(diǎn)我們后續(xù)會(huì)詳細(xì)解釋。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public int read() throws ioexception {
 char cb[] = new char[1];
 if (read(cb, 0, 1) == -1)
 return -1;
 else
 return cb[0];
}
 
public int read(char cbuf[]) throws ioexception {
 return read(cbuf, 0, cbuf.length);
}
 
abstract public int read(char cbuf[], int off, int len)

基本的讀字符操作都在這了,第一個(gè)方法用于讀取一個(gè)字符出來(lái),如果已經(jīng)讀到了文件末尾,將返回 -1,同樣的以 int 作為返回值類型接收,為什么不用 char?原因是一樣的,都是由于 -1 這個(gè)值的解釋不確定性。

第二個(gè)方法和第三個(gè)方法是類似的,從文件中讀取指定長(zhǎng)度的字符放置到目標(biāo)數(shù)組當(dāng)中。第三個(gè)方法是抽象方法,需要子類自行實(shí)現(xiàn),而第二個(gè)方法卻又是基于它的。

還有一些方法也是類似的:

  • public long skip(long n):跳過(guò) n 個(gè)字符
  • public boolean ready():下一個(gè)字符是否可讀
  • public boolean marksupported():見(jiàn) reset 方法
  • public void mark(int readaheadlimit):見(jiàn) reset 方法
  • public void reset():用于實(shí)現(xiàn)重復(fù)讀操作
  • abstract public void close():關(guān)閉流

這些個(gè)方法其實(shí)都見(jiàn)名知意,并且和我們的 inputstream 大體上都差不多,都沒(méi)有什么核心的實(shí)現(xiàn),這里不再贅述,你大致知道它內(nèi)部有些個(gè)什么東西即可。

writer 是寫(xiě)的字符流,它用于將一個(gè)或多個(gè)字符寫(xiě)入到文件中,當(dāng)然具體的 write 方法依然是一個(gè)抽象的方法,待子類來(lái)實(shí)現(xiàn),所以我們這里亦不再贅述了。

適配器 inpuststramreader/outputstreamwriter

適配器字符流繼承自基類 reader 或 writer,它們算是字符流體系中非常重要的成員了。主要的作用就是,將一個(gè)字節(jié)流轉(zhuǎn)換成一個(gè)字符流,我們先以讀適配器為例。

首先就是它最核心的成員:

?
1
private final streamdecoder sd;

streamdecoder 是一個(gè)解碼器,用于將字節(jié)的各種操作轉(zhuǎn)換成字符的相應(yīng)操作,關(guān)于它我們會(huì)在后續(xù)的介紹中不間斷的提到它,這里不做統(tǒng)一的解釋。

然后就是構(gòu)造器:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public inputstreamreader(inputstream in) {
 super(in);
 try {
 sd = streamdecoder.forinputstreamreader(in, this, (string)null);
 } catch (unsupportedencodingexception e) {
 throw new error(e);
 }
}
 
public inputstreamreader(inputstream in, string charsetname)
 throws unsupportedencodingexception
{
 super(in);
 if (charsetname == null)
 throw new nullpointerexception("charsetname");
 sd = streamdecoder.forinputstreamreader(in, this, charsetname);
}

這兩個(gè)構(gòu)造器的目的都是為了初始化這個(gè)解碼器,都調(diào)用的方法 forinputstreamreader,只是參數(shù)不同而已。我們不妨看看這個(gè)方法的實(shí)現(xiàn):

Java基礎(chǔ)教程之字符流文件讀寫(xiě)

這是一個(gè)典型的靜態(tài)工廠模式,三個(gè)參數(shù),var0 和 var1 沒(méi)什么好說(shuō)的,分別代表的是字節(jié)流實(shí)例和適配器實(shí)例。

而參數(shù) var2 其實(shí)代表的是一種字符編碼的名稱,如果為 null,那么將使用系統(tǒng)默認(rèn)的字符編碼:utf-8 。

最終我們能夠得到一個(gè)解碼器實(shí)例。

接著介紹的所有方法幾乎都是依賴的這個(gè)解碼器而實(shí)現(xiàn)的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public string getencoding() {
 return sd.getencoding();
}
 
public int read() throws ioexception {
 return sd.read();
}
 
public int read(char cbuf[], int offset, int length){
 return sd.read(cbuf, offset, length);
}
 
public void close() throws ioexception {
 sd.close();
}

解碼器中相關(guān)的方法的實(shí)現(xiàn)代碼還是相對(duì)復(fù)雜的,這里我們不做深入的研究,但大體上的實(shí)現(xiàn)思路就是:「字節(jié)流讀取 + 解碼」的過(guò)程。

當(dāng)然了,outputstreamwriter 中必然也存在一個(gè)相反的 streamencoder 實(shí)例用于編碼字符。

除了這一點(diǎn)外,其余的操作并沒(méi)有什么不同,或是通過(guò)字符數(shù)組向文件中寫(xiě)入,或是通過(guò)字符串向文件中寫(xiě)入,又或是通過(guò) int 的低 16 位向文件中寫(xiě)入。

文件字符流 filereader/writer

文件的字符流可以說(shuō)非常簡(jiǎn)單了,除了構(gòu)造器,就不存在任何其他方法了,完全依賴文件字節(jié)流。

我們以 filereader 為例,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
filereader 繼承自 inputstreamreader,有且僅有以下三個(gè)構(gòu)造器:
 
public filereader(string filename) throws filenotfoundexception {
 super(new fileinputstream(filename));
}
 
public filereader(file file) throws filenotfoundexception {
 super(new fileinputstream(file));
}
 
public filereader(filedescriptor fd) {
 super(new fileinputstream(fd));
}

理論上來(lái)說(shuō),所有的字符流都應(yīng)當(dāng)以我們的適配器為基類,因?yàn)橹挥兴峁┝俗址阶止?jié)之間的轉(zhuǎn)換,無(wú)論你是寫(xiě)或是讀都離不開(kāi)它。

而我們的 filereader 并沒(méi)有擴(kuò)展任何一個(gè)自己的方法,父類 inputstreamreader 中預(yù)實(shí)現(xiàn)的字符操作方法對(duì)他來(lái)說(shuō)已經(jīng)足夠,只需要傳入一個(gè)對(duì)應(yīng)的字節(jié)流實(shí)例即可。

filewriter 也是一樣的,這里不再贅述了。

字符數(shù)組流 chararrayreader/writer

字符數(shù)組和字節(jié)數(shù)組流是類似的,都是用于解決那種不確定文件大小,而需要讀取其中大量?jī)?nèi)容的情況。

由于它們內(nèi)部提供動(dòng)態(tài)擴(kuò)容機(jī)制,所以既可以完全容納目標(biāo)文件,也可以控制數(shù)組大小,不至于分配過(guò)大內(nèi)存而浪費(fèi)了大量?jī)?nèi)存空間。

先以 chararrayreader 為例

?
1
2
3
4
5
6
7
8
9
10
11
protected char buf[];
 
public chararrayreader(char buf[]) {
 this.buf = buf;
 this.pos = 0;
 this.count = buf.length;
}
 
public chararrayreader(char buf[], int offset, int length){
 //....
}

構(gòu)造器核心任務(wù)就是初始化一個(gè)字符數(shù)組到內(nèi)部的 buf 屬性中,以后所有對(duì)該字符數(shù)組流實(shí)例的讀操作都基于 buf 這個(gè)字符數(shù)組。

關(guān)于 chararrayreader 的其他方法以及 chararraywriter,這里不再贅述了,和上篇的字節(jié)數(shù)組流基本類似。

除此之外,這里還涉及一個(gè) stringreader 和 stringwriter,其實(shí)本質(zhì)上和字符數(shù)組流是一樣的,畢竟 string 的本質(zhì)就是 char 數(shù)組。

緩沖數(shù)組流 bufferedreader/writer

同樣的,bufferedreader/writer 作為一種緩沖流,也是裝飾者流,用于提供緩沖功能。大體上類似于我們的字節(jié)緩沖流,這里我們簡(jiǎn)單介紹下。

?
1
2
3
4
5
6
7
8
9
private reader in;
private char cb[];
private static int defaultcharbuffersize = 8192;
 
public bufferedreader(reader in, int sz){..}
 
public bufferedreader(reader in) {
 this(in, defaultcharbuffersize);
}

cb 是一個(gè)字符數(shù)組,用于緩存從文件流中讀取出來(lái)的部分字符,你可以在構(gòu)造器中初始化這個(gè)數(shù)組的長(zhǎng)度,否則將使用默認(rèn)值 8192 。

?
1
2
3
public int read() throws ioexception {..}
 
public int read(char cbuf[], int off, int len){...}

關(guān)于 read,它依賴成員屬性 in 的讀方法,而 in 作為一個(gè) reader 類型,內(nèi)部往往又依賴的某個(gè) inputstream 實(shí)例的讀方法。

所以說(shuō),幾乎所有的字符流都離不開(kāi)某個(gè)字節(jié)流實(shí)例。

關(guān)于 bufferedwriter,這里也不再贅述了,大體上都是類似的,只不過(guò)一個(gè)是讀一個(gè)是寫(xiě)而已,都圍繞著內(nèi)部的字符數(shù)組進(jìn)行。

標(biāo)準(zhǔn)打印輸出流

打印輸出流主要有兩種,printstream 和 printwriter,前者是字節(jié)流,后者是字符流。

這兩個(gè)流算是對(duì)各自類別下的流做了一個(gè)集成,內(nèi)部封裝有豐富的方法,但實(shí)現(xiàn)也稍顯復(fù)雜,我們先來(lái)看這個(gè) printstream 字節(jié)流:

主要的構(gòu)造器有這么幾個(gè):

  • public printstream(outputstream out)
  • public printstream(outputstream out, boolean autoflush)
  • public printstream(outputstream out, boolean autoflush, string encoding)
  • public printstream(string filename)

顯然,簡(jiǎn)單的構(gòu)造器會(huì)依賴復(fù)雜的構(gòu)造器,這已經(jīng)算是 jdk 設(shè)計(jì)「老套路」了。區(qū)別于其他字節(jié)流的一點(diǎn)是,printstream 提供了一個(gè)標(biāo)志 autoflush,用于指定是否自動(dòng)刷新緩存。

接著就是 printstream 的寫(xiě)方法:

  • public void write(int b)
  • public void write(byte buf[], int off, int len)

除此之外,printstream 還封裝了大量的 print 的方法,寫(xiě)入不同類型的內(nèi)容到文件中,例如:

  • public void print(boolean b)
  • public void print(char c)
  • public void print(int i)
  • public void print(long l)
  • public void print(float f)
  • 等等

當(dāng)然,這些方法并不會(huì)真正的將數(shù)值的二進(jìn)制寫(xiě)入文件,而只是將它們所對(duì)應(yīng)的字符串寫(xiě)入文件,例如:

?
1
print(123);

最終寫(xiě)入文件的不是 123 所對(duì)應(yīng)的二進(jìn)制表述,而僅僅是 123 這個(gè)字符串,這就是打印流。

printstream 使用的緩沖字符流實(shí)現(xiàn)所有的打印操作,如果指明了自動(dòng)刷新,則遇到換行符號(hào)「\n」會(huì)自動(dòng)刷新緩沖區(qū)。

所以說(shuō),printstream 集成了字節(jié)流和字符流中所有的輸出方法,其中 write 方法是用于字節(jié)流操作,print 方法用于字符流操作,這一點(diǎn)需要明確。

至于 printwriter,它就是全字符流,完全針對(duì)字符進(jìn)行操作,無(wú)論是 write 方法也好,print 方法也好,都是字符流操作。

總結(jié)一下,我們花了三篇文章講解了 java 中的字節(jié)流和字符流操作,字節(jié)流基于字節(jié)完成磁盤(pán)和內(nèi)存之間的數(shù)據(jù)傳輸,最典型的就是文件字符流,它的實(shí)現(xiàn)都是本地方法。有了基本的字節(jié)傳輸能力后,我們還能夠通過(guò)緩沖來(lái)提高效率。

而字符流的最基本實(shí)現(xiàn)就是,inputstreamreader 和 outputstreamwriter,理論上它倆就已經(jīng)能夠完成基本的字符流操作了,但也僅僅局限于最基本的操作,而構(gòu)造它們的實(shí)例所必需的就是「一個(gè)字節(jié)流實(shí)例」+「一種編碼格式」。

所以,字符流和字節(jié)流的關(guān)系也就如上述的等式一樣,你寫(xiě)一個(gè)字符到磁盤(pán)文件中所必需的步驟就是,按照指定編碼格式編碼該字符,然后使用字節(jié)流將編碼后的字符二進(jìn)制寫(xiě)入文件中,讀操作是相反的。

文章中的所有代碼、圖片、文件都云存儲(chǔ)在我的 github 上:

(https://github.com/singleyam/overview_java)

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:https://www.cnblogs.com/yangming1996/p/9072330.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 8天堂资源在线官网 | tiny4k欧美极品在线 | 国产美女久久精品香蕉69 | 非洲黑人女bbwxxxx | 国产黄频在线观看高清免费 | 精新精新国产自在现拍 | 色综合久久天天综合 | 国内交换一区二区三区 | 四虎影视地址 | 99精彩免费观看 | 91视频完整版 | 亚洲日本va午夜中文字幕 | 青草国产福利视频免费观看 | 欧美一级久久久久久久大片 | 亚洲免费大全 | 国产在线观看精品香蕉v区 国产在线观看a | 男生同性啪视频在线观看 | 特级淫片欧美高清视频蜜桃 | 亚洲精品青青草原avav久久qv | 九九99九九精彩 | 精品国产成人a区在线观看 精品高潮呻吟99AV无码视频 | 国产成人久久精品一区二区三区 | 成人影院在线观看免费 | 女同69式互添在线观看免费 | 亚洲成人中文 | 日韩一区二三区无 | 性关系视频免费网站在线观看 | 国产精品嫩草影院一二三区入口 | 欧美特欧美特级一片 | yellow视频在线观看免费 | 亚洲日本中文字幕天天更新 | 国产a高清 | 96av视频在线观看 | sss亚洲国产欧美一区二区 | 日本色吧| 五月天在线视频观看 | 91综合精品网站久久 | 蜜桃88av| 精品久久久久久久久久久 | 国产一区二区视频在线 | 狠狠燥 |