新聞中心
本文轉(zhuǎn)載自微信公眾號「小菜良記」,作者蔡不菜丶 。轉(zhuǎn)載本文請聯(lián)系小菜良記公眾號。

10年積累的成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先建設(shè)網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有五華免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
前言:
對程序語言的設(shè)計者來說,創(chuàng)建一個好的輸入/輸出 (I/O) 系統(tǒng)是一項艱難的任務(wù)
Java IO:即 Java 輸入/輸出系統(tǒng)。大部分程序都需要處理一些輸入,并由輸入產(chǎn)生一些輸出,因此Java為我們提供了 java.io 包
作為一個合格的程序開發(fā)者,說到 IO 我們并不會陌生,JAVA IO 系統(tǒng)的知識體系如下:
看完以上的圖,才會恍然,原來 Java.io 包中為我們提供了這么多支持。而我們恍然的同時也不必感到驚慌,俗話說萬變不離其宗,我們只需要根據(jù)源頭進(jìn)行擴(kuò)展,相信就可以很好的掌握IO知識體系。
File類
讀寫操作少不了與文件(File)打交道,因此我們想要掌握好 IO 流,不妨先從文件入手。
文件(File)這個詞即非單數(shù)也非復(fù)數(shù),它既能代表一個特殊的文件,又能表示一個目錄下的文件集。
列表
File 如果表示的是一個目錄下的文件集的時候,我們想要得到一個目錄可以怎么做?
File已經(jīng)為我們準(zhǔn)備好了 API,根據(jù)返回值類型,我們不難猜到每個 API 方法的用處。
已知我們 D 盤目錄下有個 TestFile 文件夾,該文件夾下有以下文件:
名稱列表
如果我們想要獲取指定目錄下的名稱列表,我們可以使用這兩個API:
list()
list(FilenameFilter filter)
不帶參數(shù)的 list() 方法默認(rèn)是列出指定目錄下的所有文件名稱。如果我們想要指定名稱的目錄名稱列表我們便可以使用另一個方法:
我們期望獲取帶有test關(guān)鍵字的文件名稱,而結(jié)果也如我們所愿。
文件列表
有時候我們的很多操作不單單針對于某個文件,而是在整個文件集上做操作。要產(chǎn)生這個文件集,那我們就需要借助 File 的另外API方法了:
listFiles()
listFiles(FilenameFilter filter)
listFiles(FileFilter filter)
有了以上經(jīng)驗,我們不難猜到 listFiles() 的作用便是列出所有的文件列表:
圖中我們已經(jīng)獲取到了文件集,該方法會返回的同樣是一個數(shù)組,不過是一個 File類型的數(shù)組。
聰明的你肯定也已經(jīng)知道了如果獲取帶指定關(guān)鍵字的文件集
與上述列出文件名稱如出一轍,真是個小機(jī)靈鬼~
但是listFiles(FileFilter filter) 這個方法傳遞的參數(shù)與上有何異?我們不妨一試:
同樣是一個接口,同樣需要重寫 accept() 方法,但是這個方法只有一個 File 的參數(shù)。因此這兩個參數(shù)都是用于文件過濾的,功能大同小異~
目錄工具
創(chuàng)建目錄
File 類的好用之處不僅能讓你對于已有目錄文件的操作,還能讓你無中生有!
文件的特性無外乎:名稱,大小,最后修改日期,可讀/寫,類型等
那么我們通過 API 也理應(yīng)能夠獲得:
以上什么類型都獲取到了,唯獨少了個類型,雖然說 File 沒有提供直接獲取類型的方法,但是我們可以通過獲取文件的全名,然后通過裁剪獲取到文件的后綴,便可獲取到文件的類型:
轉(zhuǎn)手一操作,自給自足也能獲取文件類型,真是個小機(jī)靈鬼~
以上我們都是基于文件目錄存在的情況下操作的,那么如果我們想要操作的文件目錄不存在?;蛘哂捎谖覀兊拇中膶⑽募夸浢Q輸入錯了,那么將會發(fā)生什么情況,操作進(jìn)程是否能夠正常進(jìn)行?
結(jié)果便是拋出異常了,的確拋出異常才是正常的現(xiàn)象,針對一個不存在的文件目錄進(jìn)行操作豈不是瞎胡鬧
因此在我們不確定文件目錄是否存在的情況下我們可以這樣操作:
在圖中我們可以看到兩個我們沒見過的API方法,分別是 exists() 和 mkdirs().
exists():用于驗證文件目錄是否存在
mkdirs():用于創(chuàng)建目錄
通過以上先驗證后操作,我們成功避免了異常。這里需要了解的是,除了 mkdirs() 可以創(chuàng)建目錄之外,還有一個 mkdir() 也是可以創(chuàng)建目錄的,這兩個方法除了少了一個 s 之外,還有其他區(qū)別呢?
mkdir(): 只能創(chuàng)建一層目錄
mkdirs(): 可以創(chuàng)建多層目錄
我們目前的場景是 Test 目錄不存在,dir01 這個目錄自然也不存在,那么這個時候就得創(chuàng)建兩層目錄。但是我們使用 mkdir() 這個方法是行不通的,它無法創(chuàng)建。因此遇到這種情況我們應(yīng)當(dāng)使用 mkdirs()這個方法。
File類型
File 可以是一個文件也可以是一個文件集,文件集中可包含一個文件或者是一個文件夾,如果我們想要針對一個文件做讀寫操作,卻無意對一個文件夾進(jìn)行了操作,那就尷尬了,因此我們可以借助 isDirectory來判斷是否是文件夾:
輸入與輸出
上面我們談到 File 類的基本操作,接下來我們便進(jìn)入了I/O模塊。
輸入和輸出我們經(jīng)常使用 流 這個概念,如輸入流和輸出流。這是個抽象的概念,代表任何與能力產(chǎn)出數(shù)據(jù)的數(shù)據(jù)源對象或是有能力接受數(shù)據(jù)的接收端對象。流 屏蔽了實際 I/O 設(shè)備找那個處理數(shù)據(jù)的細(xì)節(jié)!
I/O 可以分為 輸入 和 輸出 兩部分。
輸入流中又分為 字節(jié)輸入流(InputStream) 和 字符輸入流(Reader),任何由 InputStream 或 Reader 派生而來的類都實現(xiàn)了 read() 這個方法,用來讀取單個字節(jié)或字節(jié)數(shù)組。
輸出流中又分為 字節(jié)輸出流(OutputStream) 和 字符輸出流(Writer),任何由 OutputStream 或 Writer 派生而來的類都實現(xiàn)了 write() 這個方法,用來寫入單個字節(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 對象 3. 文件 4. “管道”(一端輸入,一端輸出)
其中每一種數(shù)據(jù)源都有對應(yīng)的 InputStream 子類可以操作:
| 類 | 功能 |
|---|---|
| ByteArrayInputStream | 允許將內(nèi)存的緩沖區(qū)當(dāng)作 InputStream 使用 |
| StringBufferInputStream | 已廢棄,將String轉(zhuǎn)換成 InputStream |
| FileInputStream | 用于從文件中讀取信息 |
| PipedInputStream | 產(chǎn)生用于寫入相關(guān) PipedOutPutStream的數(shù)據(jù),實現(xiàn) 管道化 的概念 |
| SequenceInputStream | 將兩個或多個 InputStream 對象轉(zhuǎn)換成一個 InputStream |
| FilterInputStream | 抽象類,作為裝飾器的接口,為其他InputStream 提供有用的功能 |
OutPutStream
該類別的類決定了輸出所要去往的目標(biāo):1. 字節(jié)數(shù)組 2. 文件 3. 管道
常見的 OutPutStream 子類有:
| 類 | 功能 |
|---|---|
| ByteArrayOutputStream | 在內(nèi)存中創(chuàng)建緩沖區(qū),所有送往 “流” 的數(shù)據(jù)都要放置在此緩沖區(qū) |
| FileOutputStream | 用于將信息寫入文件 |
| PipedOutputStream | 任何寫入其中的信息都會自動作為相關(guān) PipedInputStream 的輸出,實現(xiàn) 管道化 的概念 |
| FilterOutputStream | 抽象類,作為裝飾器 的接口,為其他 OutputStream 提供有用的功能 |
裝飾器
我們通過以上的認(rèn)識,都看到了不管是輸入流還是輸出流,其中都有一個抽象類FilterInputStream 和 FilterOutputStream,這些類相當(dāng)于是一個裝飾器。在Java 中I/O 操作需要多種不同的功能組合,而這個便是使用裝飾器模式的理由所在。
何為裝飾器?裝飾器必須具有和它所裝飾對象的相同接口,但它也可以擴(kuò)展接口,它可以給我們提供了相當(dāng)多的靈活性,但它也會增加代碼的復(fù)雜性。
FilterInputStream 和FilterOutputStream 是用來提供裝飾器類接口以控制特定輸入流(InputStream)和輸出流(OutputStream)的兩個類。
FilterInputStream
InputStream 作為字節(jié)輸入流,那么讀取的數(shù)據(jù)理應(yīng)用字節(jié)數(shù)組接收,如下:
我們得借助一個 byte 數(shù)組來接收讀取到值,然后轉(zhuǎn)為字符串類型。
既然我們有了裝飾器FilterInputStream ,那是否可以借助裝飾器的子類來幫我們實現(xiàn)讀操作呢?我們先來看下常用的FilterInputStream子類有哪些:
| 類 | 功能 |
|---|---|
| DataInputStream | 與 DataOutputStream 搭配使用,我們可以按照可移植方式從流讀取基本數(shù)據(jù)類型(int,char,long) |
| BufferedInputStream | 使用它可以防止每次讀取時都得進(jìn)行實際寫操作。代表"緩沖區(qū)" |
其中DataInputStream允許我們讀取不同的基本數(shù)據(jù)類型數(shù)據(jù)以及String對象,搭配相應(yīng)的DataOutputStream,我們就可以通過數(shù)據(jù)"流" 將基本類型的數(shù)據(jù)從一個地方遷移到另一個地方。
然后說到BufferedInputStream 之前我們先看一組測試代碼:
現(xiàn)有三個文本文件,其中test01.txt 大小約為 610M,test02/test03均為空文本文件
那我們現(xiàn)在分別用普通的 InputStream + OutputStream 和裝飾后的BufferedInputStream + BufferedOutputStream 寫入文本
普通組合:
緩沖區(qū)組合:
可以看出兩種方式的分別耗時,4864 ms 和 1275 ms。使用普通組合相當(dāng)于是緩沖區(qū)的 4 倍之久,如果文件更大的話,這個差異可是驚人的!驚訝的同時肯定也有所詫異,這是為什么呢?
如果用read()方法讀取一個文件,每讀取一個字節(jié)就要訪問一次硬盤,這種讀取的方式效率是很低的。即便使用read(byte b[])方法一次讀取多個字節(jié),當(dāng)讀取的文件較大時,也會頻繁的對磁盤操作。
而BufferedInputStream的API文檔解釋為:在創(chuàng)建BufferedInputStream時,會創(chuàng)建一個內(nèi)部緩沖區(qū)數(shù)組。在讀取流中的字節(jié)時,可根據(jù)需要從包含的輸入流再次填充該內(nèi)部緩沖區(qū),一次填充多個字節(jié)。也就是說,Buffered類初始化時會創(chuàng)建一個較大的byte數(shù)組,一次性從底層輸入流中讀取多個字節(jié)來填充byte數(shù)組,當(dāng)程序讀取一個或多個字節(jié)時,可直接從byte數(shù)組中獲取,當(dāng)內(nèi)存中的byte讀取完后,會再次用底層輸入流填充緩沖區(qū)數(shù)組。因此這種從直接內(nèi)存中讀取數(shù)據(jù)的方式要比每次都訪問磁盤的效率高很多。
BufferedInputStream/BufferedOutputStream不直接操作數(shù)據(jù)源,而是對其他字節(jié)流進(jìn)行包裝,它們是 處理流。
程序把數(shù)據(jù)保存到 BufferedOutputStream 緩沖區(qū)中,并沒有立即保存到文件里,緩沖區(qū)中的數(shù)組在以下情況會保存到文件中:
緩沖區(qū)已滿
- flush() 清空緩沖區(qū)
- close() 關(guān)閉流
- FilterOutputStream
OutputStream 的基本操作如下:
通過調(diào)用write() 方法便可將值寫入文件中,這里有兩點需要注意:
- 寫入文檔默認(rèn)是覆蓋的方式
按我們理解調(diào)用兩次該方法,文本文件中的內(nèi)容應(yīng)該是兩行 公眾號:小菜良記,但是實際上只用一行,這是因為后面寫入的內(nèi)容會覆蓋前面已經(jīng)存在的內(nèi)容,解決方法便是在構(gòu)造函數(shù)的時候加上append = true
寫入與讀取的區(qū)別在于,讀取的時候如果文件不存在會報錯,但是寫入的時候如果文件不存在,會默認(rèn)幫你創(chuàng)建文件
OutputStream中同樣存在裝飾器類FilterOutputStream,以下便是裝飾器類的常用子類:
| 類 | 功能 |
|---|---|
| DataOutputStream | 與DATAInputStream搭配使用,可以按照可移植方式向流中寫入基本類型數(shù)據(jù)(int,char,long等) |
| BufferedOutputStream | 使用它避免每次發(fā)送數(shù)據(jù)時都要進(jìn)行實際的寫操作,代表 使用緩沖區(qū),可以調(diào)用flush清空緩沖區(qū) |
DataOutputStream 和 BufferedOutputStream 在上面已經(jīng)講到,這里就不再贅述。
Reader 與 Writer
在 Java 1.1 的時候,對基本的I/O流類庫進(jìn)行了重大的修改,增添了 Reader 和 Writer 兩個類。在我之前局限的認(rèn)知中,會誤以為這兩個類的出現(xiàn)是為了替代 InputStream 和 OutputStream ,但事實也并非與我局限認(rèn)知所似。
InputStream 和 OutputStream 是以面向字節(jié)的形式為 I/O 提供功能,而 Reader 和 Writer是提供兼容 Unicode于面向字符的形式為 I/O 提供功能
這兩者共存,并提供了適配器 - InputStreamReader 和 OutputStreamWriter
- InputStreamReader 可以把 InputStream 轉(zhuǎn)換為 Reader
- OutputStreamWriter 可以把 OutputStream 轉(zhuǎn)換為 Writer
這兩者雖然不能說完全相同,但也是極為相似,對照如下:
| 字節(jié)流 | 字符流 |
|---|---|
| InputStream | Reader |
| OutputStream | Writer |
| FileInputStream | FileReader |
| FileOutputStream | FileWriter |
| ByteArrayInputStream | CharArrayReader |
| ByteArrayOutputStream | CharArrayWriter |
| PipedInputStream | PipedReader |
| PipedOutputStream | PipedWriter |
甚至裝飾者類都幾乎相似:
| 字節(jié)流 | 字符流 |
|---|---|
| FilterInputStream | FilterReader |
| FilterOutputStream | FilterWriter |
| BufferedInputStream | BufferedReader |
| BufferedOutputStream | BufferedWriter |
| PrintStream | PrintWriter |
使用Reader 和 Writer 的方式也十分簡單:
我們順便看下裝飾器的使用BufferedReader 與 BufferedWriter
RandomAccessFile
RandomAccessFile 適用于由大小已知的記錄組成的文件,所以我們可以使用 seek() 將記錄從一處轉(zhuǎn)移到另一處,然后讀取或者修改記錄。文件中記錄的大小不一定都相同,只要我們能夠確定哪些記錄有多大以及它們在文件中的位置即可。
我們從圖中可以看到 RandomAccessFile 并非繼承于 InputStream 和 OutputStream 兩個接口,而是繼承于有些陌生的DateInput 和 DataOutput。
真是個有點特立獨行的類~我們繼續(xù)來看下它的構(gòu)造函數(shù):
我們這邊只截取了構(gòu)造函數(shù)的一部分,畢竟只截重點就行~
觀察構(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 這個類什么都要。既能讀,又能寫
從本質(zhì)上來說,RandomAccessFile 的工作方式類似于把 DataInputStream 和 DataOutputStream 組合起來使用,還添加了一些方法,其中方法getFilePointer() 用于查找當(dāng)前所處的文件位置,seek()用于在文件內(nèi)移至新的位置,length() 用于判斷文件的最大尺寸。第二個參數(shù)用于表明我們是 "隨機(jī)讀(r)" 還是 "既讀又寫(rw)",但它不支持單獨 寫文件。我們實際來操作一下:
獲取只讀RandomAccessFile:
獲取可讀可寫RandomAccessFile
我們首先從向文件中寫入了test 四個單詞,然后將頭指針移動3位后繼續(xù)寫入File四個單詞,結(jié)果就變成了testFile,這是因為移動指針后是以第四個位置開始寫入。
ZIP
看到zip這個詞,我們理所應(yīng)當(dāng)?shù)木蜁氲綁嚎s文件,沒錯壓縮文件在 Java I/O中也是極其重要的存在。也許更應(yīng)該說對文件的壓縮在我們的開發(fā)中也是極其重要的存在。
在 Java 內(nèi)置類中提供了需要關(guān)于ZIP 壓縮的類,可以使用 java.util.zip 包中的ZipOutuputStream 和 ZipInputStream 來實現(xiàn)文件的 壓縮 和 解壓縮。我們先來看下如何對文件進(jìn)行壓縮~
ZipOutputStream
ZipOutputStream 的構(gòu)造方法如下:
- public ZipOutputStream(OutputStream out) {/* doSomething */}
我們需要傳入一個 OutputStream 對象。因此我們也大致可以認(rèn)為 壓縮文件 相當(dāng)于是向一個 壓縮文件中寫入數(shù)據(jù),聽起來可能會有點繞。我們先看下ZipOutputStream中有哪些API:
| 方法 | 返回值 | 說明 |
|---|---|---|
| putNextEntry(ZipEntry e) | void | 開始寫一個新的 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 |
我們來演示一下如何壓縮文件:
場景:我們需要將D盤目錄下的 TestFile文件夾壓縮到 D盤下的 test.zip 中
具體的操作邏輯如下:
通過以上步驟我們便可以很順利的將一個文件壓縮
ZipInputStream
說完如何將文件壓縮,那自然要會如何將文件解壓縮!
- public ZipInputStream(InputStream in) {/* doSomethings */}
ZipInputStream 與壓縮流類似,構(gòu)造函數(shù)同樣需要傳入一個 InputStream 對象,毋庸置疑,API肯定也是一一對應(yīng)的:
| 方法 | 返回值 | 說明 |
|---|---|---|
| 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 條目并定位流以讀取下一個條目 |
| skip(long n) | long | 跳過當(dāng)前 ZIP 條目中指定的字節(jié)數(shù) |
| getNextEntry() | ZipEntry | 讀取下一個ZipEntry,并將流內(nèi)的位置移至該 entry 所指數(shù)據(jù)的開頭 |
| createZipEntry(String name) | ZipEntry | 以指定的name參數(shù)新建一個ZipEntry對象 |
那下面我們便動手操作一下如何解壓一個文件:
不必被代碼長度嚇到,認(rèn)真閱讀便會發(fā)現(xiàn)解壓文件也很簡單:
我們通過 getNextEntry() 方法來獲取到一個ZipEntry,這里取到文件方式類似于深度遍歷,每次返回的目錄大致如下:
每次都會遍歷完一個目錄下的所有文件,例如 dir01 文件夾下的所有文件,才會繼續(xù)遍歷 dir02 文件夾,所以我們不必使用遞歸的方式去獲取所有文件。取到每一個文件后,通過 ZipFile獲取輸出流,然后寫入到解壓后的文件中。大致流程如下:
新 I/O
JDK1.4的java.nio.* 包中引入了新的 JavaI/O 類庫,其目的也簡單,就是提高速度。實際上,舊的I/O包已經(jīng)使用 nio 重新實現(xiàn)過,以便充分利用這種速度提高。
只要使用的結(jié)構(gòu)更接近于操作系統(tǒng)執(zhí)行I/O的方式,那么速度自然也會提高,因此就產(chǎn)生了兩個概念:通道 和 緩沖器。
我們該怎么理解 通道 和 緩沖器 兩個概念呢。我們可以認(rèn)為緩沖器相當(dāng)于是一輛煤礦中的小火車,通道相當(dāng)于火車的軌道,小火車載著滿滿的煤礦從礦源運往它處。因此我們并沒有直接和通道交互,而是和緩沖器交互,并把緩沖器派送到通道。通道要么從緩沖器獲得數(shù)據(jù),要么向緩沖器發(fā)送數(shù)據(jù)。
ByteBuffer是唯一直接與通道直接交互的緩沖器,可以存儲未加工字節(jié)的緩沖器。
- ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer 的創(chuàng)建方式通??梢酝ㄟ^allocate()方法來指定大小創(chuàng)建。同時ByteBuffer中支持 4中創(chuàng)建 ByteBuffer
為了更好支持 新I/O ,舊 I/O 類庫中有三個類被修改了,用以產(chǎn)生FileChannel。這個被修改的類分別的:FileInputStream,F(xiàn)ileOutputStream以及用于讀寫兼?zhèn)涞?RandomAccessFile。這里值得注意的是這些都是字節(jié)操作流,因為字符流不能用于產(chǎn)生通道,但是 Channels 中提供了實用的方法,用于在通道中產(chǎn)生 Reader 和 Writer
獲取通道
我們在上面已經(jīng)了解到了有三個類支持產(chǎn)生通道,具體產(chǎn)生通道的方法如下:
以上便是創(chuàng)建通道的三種方式,并且進(jìn)行了讀寫操作的測試。我們看一下圖中的測試代碼,然后總結(jié)一下:
- getChannel()方法將會產(chǎn)生一個 FileChannel。我們可以向它傳送可用于讀寫的ByteBuffer。我們將字節(jié)存放于 ByteBuffer 的方法之一是:使用 put()方法直接對它們進(jìn)行填充,填入一個或多個字節(jié),或基本數(shù)據(jù)類型的值。不過,也可以使用 wray()方法將已存在的字節(jié)數(shù)組 "包裝" 到 ByteBuffer 中。這樣子就可以不用在復(fù)制底層的數(shù)組,而是把它作為所產(chǎn)生的 ByteBuffer 的存儲器,可以稱之為 數(shù)組支持的ByteBuffer
- 我們還可以看到 FileChannel 使用到的 position() 方法,這個方法可以在文件內(nèi)隨處移動FileChannel,在這里,我們把它移動到最后,然后進(jìn)行其他的讀寫操作。
- 對于只讀訪問,我們必須顯式地使用靜態(tài)的allocate() 方法來分配 ByteBuffer。如果我們想要獲取更好的速度我們也可以使用 allocateDirect() ,以產(chǎn)生一個與操作系統(tǒng)有更高耦合性的 "直接" 緩沖器。但是這種分配的開支會更大,并且具體實現(xiàn)也隨操作系統(tǒng)的不同而不同。
- 如果我們想要的調(diào)用 read() 來向ByteBuffer 存儲字節(jié),就必須調(diào)用緩沖器上的flip() 方法,這是用來告知 FileChannel ,讓它準(zhǔn)備好讓別人讀取字節(jié)的準(zhǔn)備,當(dāng)然,這也是為了獲取最大速度。這里我們用 ByteBuffer 來接收字節(jié)后就沒有繼續(xù)使用緩沖器來進(jìn)一步操作,如果需要繼續(xù)read() 的話,我們就必須得調(diào)用 clear() 方法來為每個 read() 方法做準(zhǔn)備。
通道相連
程序員往往都是比較懶惰的,上面那種讀取后再通知 FileChannel 的方式似乎有些麻煩。那么有沒有更加簡單的方法?肯定是有的,不然我也不會問是吧~ 那就是讓一個通道與另外一個通道直接相連接,這就得借助特殊的方法transferTo() 和 transferFrom() 。具體使用如下:
借助方法1 或 方法2 都可以成功將文件寫入到 test03.txt 文件中
I/O 操作是我們?nèi)粘i_發(fā)中或不可缺的知識,所以這塊我們也得好好掌握!
文章名稱:別大意,你可能還沒掌握好JavaIO
文章網(wǎng)址:http://www.dlmjj.cn/article/cdodsje.html


咨詢
建站咨詢
