Java 輸入流中的read(byte[] b)方法詳解
我就廢話不多說(shuō)了,大家還是直接看代碼吧~
public int read(byte[] b) throws IOException
從一個(gè)輸入流中讀取一定數(shù)量的字節(jié),并將這些字節(jié)存儲(chǔ)到其緩沖作用的數(shù)組b中。這個(gè)函數(shù)會(huì)返回一次性讀取的字節(jié)數(shù)。
這個(gè)函數(shù)是一個(gè)阻塞式的函數(shù),當(dāng)它讀到有效數(shù)據(jù)、確認(rèn)的文件尾(EOF)或者拋出一個(gè)異常時(shí)它才會(huì)執(zhí)行其他語(yǔ)句,否則一直停在read()函數(shù)處等待。
比如下面的列子:
ServerSocket server = new ServerSocket(port) Socket client = server.accept(); BufferedInputStream bis = new BufferedInputStream(client.getInputStream);
byte[] box = new byte[1024]; int len = 0; while(-1!=(len = bis.read(box))) { System.out.println(len); String msg = new String(box, 0, len); }語(yǔ)句1;語(yǔ)句二;
在這種情況下,當(dāng)從客戶端接收了一條信息并轉(zhuǎn)成msg字符串后,while循環(huán)會(huì)又回到read()函數(shù),不會(huì)跳出循環(huán)執(zhí)行語(yǔ)句一和二。
因?yàn)檫@時(shí)read()函數(shù)并沒(méi)有遇到文件尾或者拋出異常,所以下一次while條件判斷read()函數(shù)會(huì)一直等待有效數(shù)據(jù)的輸入,而不是返回-1。此時(shí)整個(gè)程序?qū)?huì)阻塞在這里。
如果我們是從文件用這個(gè)函數(shù)以這種while循環(huán)方式讀取數(shù)據(jù)的話并不會(huì)遇到這個(gè)問(wèn)題,因?yàn)樽x到最后會(huì)遇到EOF的。
如果用這種方式讀取控制臺(tái)的輸入的話,我們可以選擇不要while循環(huán)?;蛘咴O(shè)置條件跳出循環(huán),即如果len小于box的長(zhǎng)度話就跳出循環(huán)。
我們還可以選擇用DataInputStream的readUTF()函數(shù)也可以。還有就是我們可以采用監(jiān)聽機(jī)制,當(dāng)監(jiān)聽到輸入流中有數(shù)據(jù)之后再讀取。
補(bǔ)充:教你完全理解IO流里的 read(),read(byte[]),read(byte[],int off,int len)以及write
好的我們先來(lái)講它們的作用,然后再用代碼來(lái)實(shí)現(xiàn)給大家看
read():
1.從讀取流讀取的是一個(gè)一個(gè)字節(jié)
2.返回的是字節(jié)的(0-255)內(nèi)的字節(jié)值
3.讀一個(gè)下次就自動(dòng)到下一個(gè),如果碰到-1說(shuō)明沒(méi)有值了.
read(byte[] bytes)
1.從讀取流讀取一定數(shù)量的字節(jié),如果比如文件總共是102個(gè)字節(jié)
2.我們定義的數(shù)組長(zhǎng)度是10,那么默認(rèn)前面10次都是讀取10個(gè)長(zhǎng)度
3.最后一次不夠十個(gè),那么讀取的是2個(gè)
4.這十一次,每次都是放入10個(gè)長(zhǎng)度的數(shù)組.
read(byte[] bytes,int off ,int len)
1.從讀取流讀取一定數(shù)量的字節(jié),如果比如文件總共是102個(gè)字節(jié)
2.我們定義的數(shù)組長(zhǎng)度是10,但是這里我們寫read(bytes,0,9)那么每次往里面添加的(將只會(huì)是9個(gè)長(zhǎng)度),就要讀12次,最后一次放入3個(gè).
3.所以一般讀取流都不用這個(gè)而是用上一個(gè)方法:read(byte[]);
下面講解write
write(int i);
直接往流寫入字節(jié)形式的(0-255)int值.
write(byte[] bytes);
往流里邊寫入緩沖字節(jié)數(shù)組中的所有內(nèi)容,不滿整個(gè)數(shù)組長(zhǎng)度的”空余內(nèi)容”也會(huì)加入,這個(gè)下面重點(diǎn)講,
write(byte[] bytes,int off,int len);
1.這個(gè)是更嚴(yán)謹(jǐn)?shù)膶懛?在外部定義len,然后每次len(為的是最后一次的細(xì)節(jié)長(zhǎng)度)都等于流往數(shù)組中存放的長(zhǎng)度
2.如上述read(bytes),前面每次都放入十個(gè),第十一次放入的是2個(gè),如果用第二種write(bytes),將會(huì)寫入輸出流十一次,每次寫入十個(gè)長(zhǎng)度,造成后面有8個(gè)空的,比原來(lái)的內(nèi)容多了
3.所以用write(byte[] bytes,int off,int len);就不會(huì)出現(xiàn)多出來(lái)的空的情況,因?yàn)樽詈笠淮蝜en不同
下面是詳細(xì)的代碼
public class Test{ public static void main(String[] args) throws Exception { UseTimeTool.getInstance().start(); FileInputStream fis = new FileInputStream("D:\\1.mp3"); FileOutputStream fos = new FileOutputStream("D:\\1copy.mp3"); //(PS:一下3個(gè)大家分開來(lái)寫和測(cè)試,為了方便我都列出來(lái)了) /*--------------不使用緩沖--------------*/ //如果不緩沖,花了差不多14"秒" int len = -1; while ((len = fis.read()) != -1) { //這里就不是長(zhǎng)度的問(wèn)題了,而是讀取的字節(jié)"內(nèi)容",讀到一個(gè)寫一個(gè),相當(dāng)慢. System.out.println("len : "+ len); fos.write(len); } /*--------------使用緩沖--------------*/ //緩沖方法復(fù)制歌曲用了不到20"毫秒" //創(chuàng)建一個(gè)長(zhǎng)度為1024的字節(jié)數(shù)組,每次都讀取5kb,目的是緩存,如果不用緩沖區(qū),用fis.read(),就會(huì)效率低,一個(gè)一個(gè)讀字節(jié),緩沖區(qū)是一次讀5000個(gè) byte[] bytes = new byte[1024*5]; //每次都是從讀取流中讀取(5k)長(zhǎng)度的數(shù)據(jù),然后再寫到文件去(5k的)數(shù)據(jù),注意,每次讀取read都會(huì)不同,是獲取到下一個(gè),直到后面最后一個(gè). while (fis.read(bytes)!=-1) { //write是最追加到文件后面,所以直接每次添5K. fos.write(bytes); } /*--------------解釋len--------------*/ //告訴你為什么用len byte[] bytes = new byte[1024*5]; int len = -1; //解釋這個(gè)fis.read(bytes)的意思:從讀取流"讀取數(shù)組長(zhǎng)度"的數(shù)據(jù)(打印len可知),并放入數(shù)組 while ((len = fis.read(bytes,0,1024)) != -1) { //雖然數(shù)組長(zhǎng)度的*5,但是這里我們?cè)O(shè)置了1024所以每次輸出1024 System.out.println("len : "+ len); //因?yàn)槊看蔚玫降氖切碌臄?shù)組,所以每次都是新數(shù)組的"0-len" fos.write(bytes,0,len); } fis.close(); fos.close(); UseTimeTool.getInstance().stop(); } }
為了方便大家,也給大家一個(gè)統(tǒng)計(jì)時(shí)間的工具類
class UseTimeTool { private static UseTimeTool utt = new UseTimeTool(); private UseTimeTool() { } public static UseTimeTool getInstance() { return utt; } private long start; public void start() { start = System.currentTimeMillis(); } public void stop() { long end = System.currentTimeMillis(); System.out.println("所用時(shí)間 : " + (end - start) + "毫秒"); } }
好了最后一個(gè):len問(wèn)題 最后多出數(shù)組不滿的部分我特再寫一個(gè)出來(lái)給大家分析
首先,文本的內(nèi)容是
public class Test{ public static void main(String[] args) throws Exception { UseTimeTool.getInstance().start(); FileInputStream fis = new FileInputStream("D:\\a.txt"); FileOutputStream fos = new FileOutputStream("D:\\acopy.txt");
不使用len:
byte[] bytes = new byte[1024*5]; while (fis.read(bytes)!=-1) { fos.write(bytes); }
得到的效果:
發(fā)現(xiàn)后續(xù)后很多的空部分,所以說(shuō)不嚴(yán)謹(jǐn)
使用len:
byte[] bytes = new byte[1024*5]; int len = -1; while ((len = fis.read(bytes,0,1024)) != -1) { fos.write(bytes,0,len); }
得到的效果
和原來(lái)一模一樣,講了那么多就是希望能幫助大家真正的理解。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Springmvc數(shù)據(jù)格式化原理及代碼案例
這篇文章主要介紹了Springmvc數(shù)據(jù)格式化原理及代碼案例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java中調(diào)用SQL Server存儲(chǔ)過(guò)程詳解
這篇文章主要介紹了Java中調(diào)用SQL Server存儲(chǔ)過(guò)程詳解,本文講解了使用不帶參數(shù)的存儲(chǔ)過(guò)程、使用帶有輸入?yún)?shù)的存儲(chǔ)過(guò)程、使用帶有輸出參數(shù)的存儲(chǔ)過(guò)程、使用帶有返回狀態(tài)的存儲(chǔ)過(guò)程、使用帶有更新計(jì)數(shù)的存儲(chǔ)過(guò)程等操作實(shí)例,需要的朋友可以參考下2015-01-01spring?cloud?eureka?服務(wù)啟動(dòng)失敗的原因分析及解決方法
這篇文章主要介紹了spring?cloud?eureka?服務(wù)啟動(dòng)失敗的原因解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03java語(yǔ)言自行實(shí)現(xiàn)ULID過(guò)程底層原理詳解
這篇文章主要為大家介紹了java語(yǔ)言自行實(shí)現(xiàn)ULID過(guò)程底層原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10詳談異步log4j2中的location信息打印問(wèn)題
這篇文章主要介紹了詳談異步log4j2中的location信息打印問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

SpringBoot使用@ResponseBody返回圖片的實(shí)現(xiàn)

SpringBoot3整合SpringDoc實(shí)現(xiàn)在線接口文檔的詳細(xì)過(guò)程