溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Java IO

發(fā)布時(shí)間:2021-10-18 10:47:51 來源:億速云 閱讀:118 作者:iii 欄目:web開發(fā)

本篇內(nèi)容主要講解“如何使用Java IO”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何使用Java IO”吧!

前言:

對(duì)程序語言的設(shè)計(jì)者來說,創(chuàng)建一個(gè)好的輸入/輸出 (I/O) 系統(tǒng)是一項(xiàng)艱難的任務(wù)

Java IO:即 Java 輸入/輸出系統(tǒng)。大部分程序都需要處理一些輸入,并由輸入產(chǎn)生一些輸出,因此Java為我們提供了 java.io 包

作為一個(gè)合格的程序開發(fā)者,說到 IO 我們并不會(huì)陌生,JAVA IO 系統(tǒng)的知識(shí)體系如下:

如何使用Java IO

看完以上的圖,才會(huì)恍然,原來 Java.io  包中為我們提供了這么多支持。而我們恍然的同時(shí)也不必感到驚慌,俗話說萬變不離其宗,我們只需要根據(jù)源頭進(jìn)行擴(kuò)展,相信就可以很好的掌握IO知識(shí)體系。

File類

讀寫操作少不了與文件(File)打交道,因此我們想要掌握好 IO 流,不妨先從文件入手。

文件(File)這個(gè)詞即非單數(shù)也非復(fù)數(shù),它既能代表一個(gè)特殊的文件,又能表示一個(gè)目錄下的文件集。

列表

File 如果表示的是一個(gè)目錄下的文件集的時(shí)候,我們想要得到一個(gè)目錄可以怎么做?

如何使用Java IO

File已經(jīng)為我們準(zhǔn)備好了 API,根據(jù)返回值類型,我們不難猜到每個(gè) API 方法的用處。

已知我們 D 盤目錄下有個(gè) TestFile 文件夾,該文件夾下有以下文件:

如何使用Java IO

名稱列表

如果我們想要獲取指定目錄下的名稱列表,我們可以使用這兩個(gè)API:

list()

list(FilenameFilter filter)

如何使用Java IO

不帶參數(shù)的 list() 方法默認(rèn)是列出指定目錄下的所有文件名稱。如果我們想要指定名稱的目錄名稱列表我們便可以使用另一個(gè)方法:

如何使用Java IO

我們期望獲取帶有test關(guān)鍵字的文件名稱,而結(jié)果也如我們所愿。

文件列表

有時(shí)候我們的很多操作不單單針對(duì)于某個(gè)文件,而是在整個(gè)文件集上做操作。要產(chǎn)生這個(gè)文件集,那我們就需要借助 File 的另外API方法了:

listFiles()

listFiles(FilenameFilter filter)

listFiles(FileFilter filter)

有了以上經(jīng)驗(yàn),我們不難猜到 listFiles() 的作用便是列出所有的文件列表:

如何使用Java IO

圖中我們已經(jīng)獲取到了文件集,該方法會(huì)返回的同樣是一個(gè)數(shù)組,不過是一個(gè) File類型的數(shù)組。

聰明的你肯定也已經(jīng)知道了如果獲取帶指定關(guān)鍵字的文件集

如何使用Java IO

與上述列出文件名稱如出一轍,真是個(gè)小機(jī)靈鬼~

但是listFiles(FileFilter filter) 這個(gè)方法傳遞的參數(shù)與上有何異?我們不妨一試:

如何使用Java IO

同樣是一個(gè)接口,同樣需要重寫 accept() 方法,但是這個(gè)方法只有一個(gè) File 的參數(shù)。因此這兩個(gè)參數(shù)都是用于文件過濾的,功能大同小異~

目錄工具

創(chuàng)建目錄

File 類的好用之處不僅能讓你對(duì)于已有目錄文件的操作,還能讓你無中生有!

文件的特性無外乎:名稱,大小,最后修改日期,可讀/寫,類型等

如何使用Java IO

那么我們通過 API 也理應(yīng)能夠獲得:

如何使用Java IO

以上什么類型都獲取到了,唯獨(dú)少了個(gè)類型,雖然說 File  沒有提供直接獲取類型的方法,但是我們可以通過獲取文件的全名,然后通過裁剪獲取到文件的后綴,便可獲取到文件的類型:

如何使用Java IO

轉(zhuǎn)手一操作,自給自足也能獲取文件類型,真是個(gè)小機(jī)靈鬼~

以上我們都是基于文件目錄存在的情況下操作的,那么如果我們想要操作的文件目錄不存在?;蛘哂捎谖覀兊拇中膶⑽募夸浢Q輸入錯(cuò)了,那么將會(huì)發(fā)生什么情況,操作進(jìn)程是否能夠正常進(jìn)行?

如何使用Java IO

結(jié)果便是拋出異常了,的確拋出異常才是正常的現(xiàn)象,針對(duì)一個(gè)不存在的文件目錄進(jìn)行操作豈不是瞎胡鬧

因此在我們不確定文件目錄是否存在的情況下我們可以這樣操作:

如何使用Java IO

在圖中我們可以看到兩個(gè)我們沒見過的API方法,分別是 exists() 和 mkdirs().

exists():用于驗(yàn)證文件目錄是否存在

mkdirs():用于創(chuàng)建目錄

通過以上先驗(yàn)證后操作,我們成功避免了異常。這里需要了解的是,除了 mkdirs() 可以創(chuàng)建目錄之外,還有一個(gè) mkdir()  也是可以創(chuàng)建目錄的,這兩個(gè)方法除了少了一個(gè) s 之外,還有其他區(qū)別呢?

mkdir(): 只能創(chuàng)建一層目錄

mkdirs(): 可以創(chuàng)建多層目錄

如何使用Java IO

我們目前的場(chǎng)景是 Test 目錄不存在,dir01 這個(gè)目錄自然也不存在,那么這個(gè)時(shí)候就得創(chuàng)建兩層目錄。但是我們使用 mkdir()  這個(gè)方法是行不通的,它無法創(chuàng)建。因此遇到這種情況我們應(yīng)當(dāng)使用 mkdirs()這個(gè)方法。

File類型

File  可以是一個(gè)文件也可以是一個(gè)文件集,文件集中可包含一個(gè)文件或者是一個(gè)文件夾,如果我們想要針對(duì)一個(gè)文件做讀寫操作,卻無意對(duì)一個(gè)文件夾進(jìn)行了操作,那就尷尬了,因此我們可以借助  isDirectory來判斷是否是文件夾:

如何使用Java IO

輸入與輸出

上面我們談到 File 類的基本操作,接下來我們便進(jìn)入了I/O模塊。

輸入和輸出我們經(jīng)常使用 流 這個(gè)概念,如輸入流和輸出流。這是個(gè)抽象的概念,代表任何與能力產(chǎn)出數(shù)據(jù)的數(shù)據(jù)源對(duì)象或是有能力接受數(shù)據(jù)的接收端對(duì)象。流 屏蔽了實(shí)際  I/O 設(shè)備找那個(gè)處理數(shù)據(jù)的細(xì)節(jié)!

I/O 可以分為 輸入 和 輸出 兩部分。

輸入流中又分為 字節(jié)輸入流(InputStream) 和 字符輸入流(Reader),任何由 InputStream 或 Reader  派生而來的類都實(shí)現(xiàn)了 read() 這個(gè)方法,用來讀取單個(gè)字節(jié)或字節(jié)數(shù)組。

輸出流中又分為 字節(jié)輸出流(OutputStream) 和 字符輸出流(Writer),任何由 OutputStream 或 Writer  派生而來的類都實(shí)現(xiàn)了 write() 這個(gè)方法,用來寫入單個(gè)字節(jié)或字節(jié)數(shù)組。

因此我們可以看出 Java 中的規(guī)定:與輸入有關(guān)的所有類都應(yīng)該從 InputStream 繼承,與輸出有關(guān)的所有類都應(yīng)該從 OutputStream  繼承

InputStream

用來表示那些從不同數(shù)據(jù)源產(chǎn)生輸入的類

那些不同數(shù)據(jù)源具體又是哪些?常見的有:1. 字節(jié)數(shù)組 2. String 對(duì)象 3. 文件 4. “管道”(一端輸入,一端輸出)

其中每一種數(shù)據(jù)源都有對(duì)應(yīng)的 InputStream 子類可以操作:

功能
ByteArrayInputStream允許將內(nèi)存的緩沖區(qū)當(dāng)作 InputStream 使用
StringBufferInputStream已廢棄,將String轉(zhuǎn)換成 InputStream
FileInputStream用于從文件中讀取信息
PipedInputStream產(chǎn)生用于寫入相關(guān) PipedOutPutStream的數(shù)據(jù),實(shí)現(xiàn) 管道化 的概念
SequenceInputStream將兩個(gè)或多個(gè) InputStream 對(duì)象轉(zhuǎn)換成一個(gè) InputStream
FilterInputStream抽象類,作為裝飾器的接口,為其他InputStream 提供有用的功能

OutPutStream

該類別的類決定了輸出所要去往的目標(biāo):1. 字節(jié)數(shù)組 2. 文件 3. 管道

常見的 OutPutStream 子類有:

功能
ByteArrayOutputStream在內(nèi)存中創(chuàng)建緩沖區(qū),所有送往 “流” 的數(shù)據(jù)都要放置在此緩沖區(qū)
FileOutputStream用于將信息寫入文件
PipedOutputStream任何寫入其中的信息都會(huì)自動(dòng)作為相關(guān) PipedInputStream 的輸出,實(shí)現(xiàn) 管道化 的概念
FilterOutputStream抽象類,作為裝飾器 的接口,為其他 OutputStream 提供有用的功能

裝飾器

我們通過以上的認(rèn)識(shí),都看到了不管是輸入流還是輸出流,其中都有一個(gè)抽象類FilterInputStream 和  FilterOutputStream,這些類相當(dāng)于是一個(gè)裝飾器。在Java 中I/O 操作需要多種不同的功能組合,而這個(gè)便是使用裝飾器模式的理由所在。

何為裝飾器?裝飾器必須具有和它所裝飾對(duì)象的相同接口,但它也可以擴(kuò)展接口,它可以給我們提供了相當(dāng)多的靈活性,但它也會(huì)增加代碼的復(fù)雜性。

FilterInputStream 和FilterOutputStream  是用來提供裝飾器類接口以控制特定輸入流(InputStream)和輸出流(OutputStream)的兩個(gè)類。

FilterInputStream

InputStream 作為字節(jié)輸入流,那么讀取的數(shù)據(jù)理應(yīng)用字節(jié)數(shù)組接收,如下:

如何使用Java IO

我們得借助一個(gè) byte 數(shù)組來接收讀取到值,然后轉(zhuǎn)為字符串類型。

既然我們有了裝飾器FilterInputStream  ,那是否可以借助裝飾器的子類來幫我們實(shí)現(xiàn)讀操作呢?我們先來看下常用的FilterInputStream子類有哪些:

功能
DataInputStream與 DataOutputStream 搭配使用,我們可以按照可移植方式從流讀取基本數(shù)據(jù)類型(int,char,long)
BufferedInputStream使用它可以防止每次讀取時(shí)都得進(jìn)行實(shí)際寫操作。代表"緩沖區(qū)"

其中DataInputStream允許我們讀取不同的基本數(shù)據(jù)類型數(shù)據(jù)以及String對(duì)象,搭配相應(yīng)的DataOutputStream,我們就可以通過數(shù)據(jù)"流"  將基本類型的數(shù)據(jù)從一個(gè)地方遷移到另一個(gè)地方。

如何使用Java IO

然后說到BufferedInputStream 之前我們先看一組測(cè)試代碼:

如何使用Java IO

現(xiàn)有三個(gè)文本文件,其中test01.txt 大小約為 610M,test02/test03均為空文本文件

那我們現(xiàn)在分別用普通的 InputStream + OutputStream 和裝飾后的BufferedInputStream +  BufferedOutputStream 寫入文本

普通組合:

如何使用Java IO

緩沖區(qū)組合:

如何使用Java IO

可以看出兩種方式的分別耗時(shí),4864 ms 和 1275 ms。使用普通組合相當(dāng)于是緩沖區(qū)的 4  倍之久,如果文件更大的話,這個(gè)差異可是驚人的!驚訝的同時(shí)肯定也有所詫異,這是為什么呢?

如果用read()方法讀取一個(gè)文件,每讀取一個(gè)字節(jié)就要訪問一次硬盤,這種讀取的方式效率是很低的。即便使用read(byte  b[])方法一次讀取多個(gè)字節(jié),當(dāng)讀取的文件較大時(shí),也會(huì)頻繁的對(duì)磁盤操作。

而BufferedInputStream的API文檔解釋為:在創(chuàng)建BufferedInputStream時(shí),會(huì)創(chuàng)建一個(gè)內(nèi)部緩沖區(qū)數(shù)組。在讀取流中的字節(jié)時(shí),可根據(jù)需要從包含的輸入流再次填充該內(nèi)部緩沖區(qū),一次填充多個(gè)字節(jié)。也就是說,Buffered類初始化時(shí)會(huì)創(chuàng)建一個(gè)較大的byte數(shù)組,一次性從底層輸入流中讀取多個(gè)字節(jié)來填充byte數(shù)組,當(dāng)程序讀取一個(gè)或多個(gè)字節(jié)時(shí),可直接從byte數(shù)組中獲取,當(dāng)內(nèi)存中的byte讀取完后,會(huì)再次用底層輸入流填充緩沖區(qū)數(shù)組。因此這種從直接內(nèi)存中讀取數(shù)據(jù)的方式要比每次都訪問磁盤的效率高很多。

如何使用Java IO

BufferedInputStream/BufferedOutputStream不直接操作數(shù)據(jù)源,而是對(duì)其他字節(jié)流進(jìn)行包裝,它們是 處理流。

程序把數(shù)據(jù)保存到 BufferedOutputStream 緩沖區(qū)中,并沒有立即保存到文件里,緩沖區(qū)中的數(shù)組在以下情況會(huì)保存到文件中:

緩沖區(qū)已滿

  • flush() 清空緩沖區(qū)

  • close() 關(guān)閉流

  • FilterOutputStream

OutputStream 的基本操作如下:

如何使用Java IO

通過調(diào)用write() 方法便可將值寫入文件中,這里有兩點(diǎn)需要注意:

  • 寫入文檔默認(rèn)是覆蓋的方式

按我們理解調(diào)用兩次該方法,文本文件中的內(nèi)容應(yīng)該是兩行  公眾號(hào):小菜良記,但是實(shí)際上只用一行,這是因?yàn)楹竺鎸懭氲膬?nèi)容會(huì)覆蓋前面已經(jīng)存在的內(nèi)容,解決方法便是在構(gòu)造函數(shù)的時(shí)候加上append = true

如何使用Java IO

寫入與讀取的區(qū)別在于,讀取的時(shí)候如果文件不存在會(huì)報(bào)錯(cuò),但是寫入的時(shí)候如果文件不存在,會(huì)默認(rèn)幫你創(chuàng)建文件

OutputStream中同樣存在裝飾器類FilterOutputStream,以下便是裝飾器類的常用子類:

功能
DataOutputStream與DATAInputStream搭配使用,可以按照可移植方式向流中寫入基本類型數(shù)據(jù)(int,char,long等)
BufferedOutputStream使用它避免每次發(fā)送數(shù)據(jù)時(shí)都要進(jìn)行實(shí)際的寫操作,代表 使用緩沖區(qū),可以調(diào)用flush清空緩沖區(qū)

DataOutputStream 和 BufferedOutputStream 在上面已經(jīng)講到,這里就不再贅述。

Reader 與 Writer

在 Java 1.1 的時(shí)候,對(duì)基本的I/O流類庫進(jìn)行了重大的修改,增添了 Reader 和 Writer  兩個(gè)類。在我之前局限的認(rèn)知中,會(huì)誤以為這兩個(gè)類的出現(xiàn)是為了替代 InputStream 和 OutputStream ,但事實(shí)也并非與我局限認(rèn)知所似。

InputStream 和 OutputStream 是以面向字節(jié)的形式為 I/O 提供功能,而 Reader 和 Writer是提供兼容  Unicode于面向字符的形式為 I/O 提供功能

這兩者共存,并提供了適配器 - InputStreamReader 和 OutputStreamWriter

  • InputStreamReader 可以把 InputStream 轉(zhuǎn)換為 Reader

  • OutputStreamWriter 可以把 OutputStream 轉(zhuǎn)換為 Writer

這兩者雖然不能說完全相同,但也是極為相似,對(duì)照如下:

字節(jié)流字符流
InputStreamReader
OutputStreamWriter
FileInputStreamFileReader
FileOutputStreamFileWriter
ByteArrayInputStreamCharArrayReader
ByteArrayOutputStreamCharArrayWriter
PipedInputStreamPipedReader
PipedOutputStreamPipedWriter

甚至裝飾者類都幾乎相似:

字節(jié)流字符流
FilterInputStreamFilterReader
FilterOutputStreamFilterWriter
BufferedInputStreamBufferedReader
BufferedOutputStreamBufferedWriter
PrintStreamPrintWriter

使用Reader 和 Writer 的方式也十分簡單:

如何使用Java IO

我們順便看下裝飾器的使用BufferedReader 與 BufferedWriter

如何使用Java IO

RandomAccessFile

RandomAccessFile 適用于由大小已知的記錄組成的文件,所以我們可以使用 seek()  將記錄從一處轉(zhuǎn)移到另一處,然后讀取或者修改記錄。文件中記錄的大小不一定都相同,只要我們能夠確定哪些記錄有多大以及它們?cè)谖募械奈恢眉纯伞?/p>

如何使用Java IO

我們從圖中可以看到 RandomAccessFile 并非繼承于 InputStream 和 OutputStream  兩個(gè)接口,而是繼承于有些陌生的DateInput 和 DataOutput。

真是個(gè)有點(diǎn)特立獨(dú)行的類~我們繼續(xù)來看下它的構(gòu)造函數(shù):

如何使用Java IO

我們這邊只截取了構(gòu)造函數(shù)的一部分,畢竟只截重點(diǎn)就行~

觀察構(gòu)造器可以發(fā)現(xiàn),這里定義了四種模式:

r以只讀的方式打開文本,也就意味著不能用write來操作文件
rw讀操作和寫操作都是允許的
rws每當(dāng)進(jìn)行寫操作,同步的刷新到磁盤,刷新內(nèi)容和元數(shù)據(jù)
rwd每當(dāng)進(jìn)行寫操作,同步的刷新到磁盤,刷新內(nèi)容

這有什么用呢?說白了就是 RandomAccessFile 這個(gè)類什么都要。既能讀,又能寫

從本質(zhì)上來說,RandomAccessFile 的工作方式類似于把 DataInputStream 和 DataOutputStream  組合起來使用,還添加了一些方法,其中方法getFilePointer() 用于查找當(dāng)前所處的文件位置,seek()用于在文件內(nèi)移至新的位置,length()  用于判斷文件的最大尺寸。第二個(gè)參數(shù)用于表明我們是 "隨機(jī)讀(r)" 還是 "既讀又寫(rw)",但它不支持單獨(dú) 寫文件。我們實(shí)際來操作一下:

獲取只讀RandomAccessFile:

如何使用Java IO

獲取可讀可寫RandomAccessFile

如何使用Java IO

我們首先從向文件中寫入了test  四個(gè)單詞,然后將頭指針移動(dòng)3位后繼續(xù)寫入File四個(gè)單詞,結(jié)果就變成了testFile,這是因?yàn)橐苿?dòng)指針后是以第四個(gè)位置開始寫入。

ZIP

看到zip這個(gè)詞,我們理所應(yīng)當(dāng)?shù)木蜁?huì)想到壓縮文件,沒錯(cuò)壓縮文件在 Java  I/O中也是極其重要的存在。也許更應(yīng)該說對(duì)文件的壓縮在我們的開發(fā)中也是極其重要的存在。

在 Java 內(nèi)置類中提供了需要關(guān)于ZIP 壓縮的類,可以使用 java.util.zip 包中的ZipOutuputStream 和  ZipInputStream 來實(shí)現(xiàn)文件的 壓縮 和 解壓縮。我們先來看下如何對(duì)文件進(jìn)行壓縮~

ZipOutputStream

ZipOutputStream 的構(gòu)造方法如下:

public ZipOutputStream(OutputStream out) {/* doSomething */}

我們需要傳入一個(gè) OutputStream 對(duì)象。因此我們也大致可以認(rèn)為 壓縮文件 相當(dāng)于是向一個(gè)  壓縮文件中寫入數(shù)據(jù),聽起來可能會(huì)有點(diǎn)繞。我們先看下ZipOutputStream中有哪些API:

如何使用Java IO

方法返回值說明
putNextEntry(ZipEntry e)void開始寫一個(gè)新的 ZipEntry,并將流內(nèi)的位置移至此 entry 所值數(shù)據(jù)的開頭
write(byte[] b, int off, int len)void將字節(jié)數(shù)組寫入當(dāng)前 ZIP 條目數(shù)據(jù)
setComment(String command)void設(shè)置此 ZIP 文件的注釋文字
finish()void完成寫入ZIP 輸出流的內(nèi)容,無須關(guān)閉它所配合的 OutputStream

我們來演示一下如何壓縮文件:

場(chǎng)景:我們需要將D盤目錄下的 TestFile文件夾壓縮到 D盤下的 test.zip 中

如何使用Java IO


如何使用Java IO

具體的操作邏輯如下:

如何使用Java IO

通過以上步驟我們便可以很順利的將一個(gè)文件壓縮

ZipInputStream

說完如何將文件壓縮,那自然要會(huì)如何將文件解壓縮!

public ZipInputStream(InputStream in) {/* doSomethings */}

ZipInputStream 與壓縮流類似,構(gòu)造函數(shù)同樣需要傳入一個(gè) InputStream 對(duì)象,毋庸置疑,API肯定也是一一對(duì)應(yīng)的:

如何使用Java IO

方法返回值說明
read(byte[] b, int off, int len)int讀取目標(biāo) b 數(shù)組內(nèi) off 偏移量的位置,長度是 len 字節(jié)
avaiable()int判斷是否已讀完目前 entry 所指定的數(shù)據(jù),已讀完返回 0,否則返回 1
closeEntry()void關(guān)閉當(dāng)前 ZIP 條目并定位流以讀取下一個(gè)條目
skip(long n)long跳過當(dāng)前 ZIP 條目中指定的字節(jié)數(shù)
getNextEntry()ZipEntry讀取下一個(gè)ZipEntry,并將流內(nèi)的位置移至該 entry 所指數(shù)據(jù)的開頭
createZipEntry(String name)ZipEntry以指定的name參數(shù)新建一個(gè)ZipEntry對(duì)象

那下面我們便動(dòng)手操作一下如何解壓一個(gè)文件:

如何使用Java IO

不必被代碼長度嚇到,認(rèn)真閱讀便會(huì)發(fā)現(xiàn)解壓文件也很簡單:

我們通過 getNextEntry() 方法來獲取到一個(gè)ZipEntry,這里取到文件方式類似于深度遍歷,每次返回的目錄大致如下:

如何使用Java IO

每次都會(huì)遍歷完一個(gè)目錄下的所有文件,例如 dir01 文件夾下的所有文件,才會(huì)繼續(xù)遍歷 dir02  文件夾,所以我們不必使用遞歸的方式去獲取所有文件。取到每一個(gè)文件后,通過 ZipFile獲取輸出流,然后寫入到解壓后的文件中。大致流程如下:

如何使用Java IO

新 I/O

JDK1.4的java.nio.* 包中引入了新的 JavaI/O 類庫,其目的也簡單,就是提高速度。實(shí)際上,舊的I/O包已經(jīng)使用 nio  重新實(shí)現(xiàn)過,以便充分利用這種速度提高。

只要使用的結(jié)構(gòu)更接近于操作系統(tǒng)執(zhí)行I/O的方式,那么速度自然也會(huì)提高,因此就產(chǎn)生了兩個(gè)概念:通道 和 緩沖器。

我們?cè)撛趺蠢斫?通道 和 緩沖器  兩個(gè)概念呢。我們可以認(rèn)為緩沖器相當(dāng)于是一輛煤礦中的小火車,通道相當(dāng)于火車的軌道,小火車載著滿滿的煤礦從礦源運(yùn)往它處。因此我們并沒有直接和通道交互,而是和緩沖器交互,并把緩沖器派送到通道。通道要么從緩沖器獲得數(shù)據(jù),要么向緩沖器發(fā)送數(shù)據(jù)。

ByteBuffer是唯一直接與通道直接交互的緩沖器,可以存儲(chǔ)未加工字節(jié)的緩沖器。

ByteBuffer buffer = ByteBuffer.allocate(1024);

ByteBuffer 的創(chuàng)建方式通常可以通過allocate()方法來指定大小創(chuàng)建。同時(shí)ByteBuffer中支持 4中創(chuàng)建 ByteBuffer

如何使用Java IO

為了更好支持 新I/O ,舊 I/O  類庫中有三個(gè)類被修改了,用以產(chǎn)生FileChannel。這個(gè)被修改的類分別的:FileInputStream,F(xiàn)ileOutputStream以及用于讀寫兼?zhèn)涞? RandomAccessFile。這里值得注意的是這些都是字節(jié)操作流,因?yàn)樽址鞑荒苡糜诋a(chǎn)生通道,但是 Channels 中提供了實(shí)用的方法,用于在通道中產(chǎn)生  Reader 和 Writer

獲取通道

我們?cè)谏厦嬉呀?jīng)了解到了有三個(gè)類支持產(chǎn)生通道,具體產(chǎn)生通道的方法如下:

如何使用Java IO

以上便是創(chuàng)建通道的三種方式,并且進(jìn)行了讀寫操作的測(cè)試。我們看一下圖中的測(cè)試代碼,然后總結(jié)一下:

  • getChannel()方法將會(huì)產(chǎn)生一個(gè) FileChannel。我們可以向它傳送可用于讀寫的ByteBuffer。我們將字節(jié)存放于 ByteBuffer  的方法之一是:使用 put()方法直接對(duì)它們進(jìn)行填充,填入一個(gè)或多個(gè)字節(jié),或基本數(shù)據(jù)類型的值。不過,也可以使用 wray()方法將已存在的字節(jié)數(shù)組 "包裝" 到  ByteBuffer 中。這樣子就可以不用在復(fù)制底層的數(shù)組,而是把它作為所產(chǎn)生的 ByteBuffer 的存儲(chǔ)器,可以稱之為  數(shù)組支持的ByteBuffer

  • 我們還可以看到 FileChannel 使用到的 position()  方法,這個(gè)方法可以在文件內(nèi)隨處移動(dòng)FileChannel,在這里,我們把它移動(dòng)到最后,然后進(jìn)行其他的讀寫操作。

  • 對(duì)于只讀訪問,我們必須顯式地使用靜態(tài)的allocate() 方法來分配 ByteBuffer。如果我們想要獲取更好的速度我們也可以使用  allocateDirect() ,以產(chǎn)生一個(gè)與操作系統(tǒng)有更高耦合性的 "直接"  緩沖器。但是這種分配的開支會(huì)更大,并且具體實(shí)現(xiàn)也隨操作系統(tǒng)的不同而不同。

  • 如果我們想要的調(diào)用 read() 來向ByteBuffer 存儲(chǔ)字節(jié),就必須調(diào)用緩沖器上的flip() 方法,這是用來告知 FileChannel  ,讓它準(zhǔn)備好讓別人讀取字節(jié)的準(zhǔn)備,當(dāng)然,這也是為了獲取最大速度。這里我們用 ByteBuffer  來接收字節(jié)后就沒有繼續(xù)使用緩沖器來進(jìn)一步操作,如果需要繼續(xù)read() 的話,我們就必須得調(diào)用 clear() 方法來為每個(gè) read() 方法做準(zhǔn)備。

通道相連

程序員往往都是比較懶惰的,上面那種讀取后再通知 FileChannel 的方式似乎有些麻煩。那么有沒有更加簡單的方法?肯定是有的,不然我也不會(huì)問是吧~  那就是讓一個(gè)通道與另外一個(gè)通道直接相連接,這就得借助特殊的方法transferTo() 和 transferFrom() 。具體使用如下:

如何使用Java IO

借助方法1 或 方法2 都可以成功將文件寫入到 test03.txt 文件中

到此,相信大家對(duì)“如何使用Java IO”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI