Java-IO

總結一些io的知識點,摘自http://ifeve.com/java-io/

1、管道和線程:

同一個JVM的兩個線程可以通過Java IO的管道通信,除了管道之外,一個JVM中不同線程之間還有許多通信的方式。實際上,線程在大多數情況下會傳遞完整的對象信息而非原始的字節數據。但是,如果需要在線程之間傳遞字節數據,Java IO的管道是一個不錯的選擇。

當使用兩個相關聯的管道流時,務必將它們分配給不同的線程。read()方法和write()方法調用時會導致流阻塞,也就是在一個線程中同時進行讀和寫,可能會導致線程死鎖。

2、不同JVM進程之間IO:

使用Java網絡API建立網絡連接,使用Java IO在進程之間交換數據。一個具有讀取文件數據功能的組件,同樣可以輕鬆讀取網絡連接中的數據。只需要保證讀取數據的組件是基於InputStream而非FileInputStream即可。

3、字節/字符數組:

用ByteArrayInputStream或者CharArrayReader封裝字節或者字符數組從數組中讀取數據。通過這種方式字節和字符就可以以數組的形式讀出了。用ByteArrayOutputStream或者CharArrayWriter,把數據寫入,就像寫其它的流一樣。當所有的數據都寫進去了以後,只要調用toByteArray()或者toCharArray,所有寫入的數據就會以數組的形式返回。

4、流處理:

流和數組不一樣,不能通過索引讀寫數據。在流中,你也不能像數組那樣前後移動讀取數據,除非使用RandomAccessFile 處理文件。流僅僅只是一個連續的數據流。流中的數據只能夠順序訪問。當達到流末尾時,返回-1。

請注意:

InputStream的read()方法返回一個字節大小,返回值的範圍在0到255之間。

Reader的read()方法返回一個字符,會根據文本的編碼,一次讀取一個或者多個字節,返回值的範圍在0到65535之間。

read(byte[])會嘗試讀取與給定字節數組容量一樣大的字節數,返回值int表示已經讀取過的字節數。如果InputStream內可讀的數據不足以填滿字節數組,那麼數組剩餘的部分將包含本次讀取之前的數據。記得檢查有多少數據實際被寫入到了字節數組中。

read(byte, int offset, int length)同樣將數據讀取到字節數組中,不同的是,該方法從數組的offset位置開始,並且最多將length個字節寫入到數組中。同樣地,read(byte, int offset, int length)方法返回一個int變量,表示有多少字節已經被寫入到字節數組中,所以請記得在讀取數據前檢查上一次調用read(byte, int offset, int length)的返回值。

5、併發IO:

IO之所以使用多線程,主要原因在於socket.accept()、socket.read()、socket.write()三個主要函數都是同步阻塞的,當一個連接在處理I/O的時候,系統是阻塞的,如果是單線程的話必然就掛死在那裏;但CPU是被釋放出來的,開啓多線程,利用多核,每個客戶端連接過來後,服務端都會啓動一個線程去處理該客戶端的請求,就可以讓CPU去處理更多的事情。其實這也是所有使用多線程的本質。

多個線程不能同時從InputStream或者Reader中讀取數據,也不能同時往OutputStream或者Writer裏寫數據。你沒有辦法保證每個線程讀取多少數據,以及多個線程寫數據時的順序。如果線程之間能夠保證操作的順序,它們可以使用同一個stream、reader、writer。比如,你有一個線程判斷當前的輸入流來自哪種類型的請求,然後將流數據傳遞給其他合適的線程做後續處理。當有序存取stream、reader、writer時,這種做法是可行的。請注意,在線程之間傳遞流數據的代碼應當是同步的。

6、輸出流的flush()

即使所有數據都寫入到了FileOutputStream,這些數據還是有可能保留在內存的緩衝區中。通過調用flush()方法,可以把緩衝區內的數據刷新到磁盤(或者網絡,以及其他任何形式的目標媒介)中。

7、RandomAccessFile:

在RandomAccessFile的某個位置讀寫之前,必須把文件指針指向該位置。通過seek()方法可以達到這一目標。可以通過調用getFilePointer()獲得當前文件指針的位置。

read()方法返回當前RandomAccessFile實例的文件指針指向的位置中包含的字節內容。

read()方法在讀取完一個字節之後,會自動把指針移動到下一個可讀字節。這意味着使用者在調用完read()方法之後不需要手動移動文件指針。與read()方法類似,write()方法在調用結束之後自動移動文件指針,所以你不需要頻繁地把指針移動到下一個將要寫入數據的位置。

IO:

DataInputStream、DataOutputStream 提了讀寫java基本類型的API。

File類:

File類只能訪問文件以及文件系統的元數據,不能讀寫文件內容。

判斷文件是否爲空,調用File.length()。

excel、word、pdf不屬於純文本文件,包含了很多格式信息,使用字節流讀取會出現亂碼,對這類文件需要使用第三方jar包。

InputStreamReader:字節流->字符流,一個字符等於兩個字節,注意編碼格式,默認操作系統字符集,否則亂碼。

使用BufferReader包裝InputStreamReader,提高效率。

OutStreamWriter:字符流->字節流,調用write()方法,使用字符編碼轉換器,在寫入輸出流之前,字節會在緩衝區緩衝,使用BufferWriter包裝OutStreamWriter避免頻繁調用轉換器。

基本流所提供的對於輸入和輸出的控制比較弱。InputStream只提供了順序讀取、跳過部分字節和標記/重置的支持,而OutputStream則只能順序輸出。

如果一個方法只是作爲流的使用者,就不需要考慮流的關閉問題。典型的情況是在servlet實現中並不需要關閉HttpServletResponse中的輸出流。

NIO:

基於Buffer進行高效io操作,Buffer是連續的堆外空間,由native代碼實現,操作系統可以直接與緩衝區交互,java程序只需要完成對緩衝區讀寫,後續操作交給操作系統完成。通過Channel,java更好的與操作系統IO服務結合起來,充分利用Buffer緩衝區,Channel不是純java實現,有native代碼

支持NIO操作的io類有FileInputStream、FileOutputStream、RandomAccessFile

NIO是基於通道(Channel)和緩衝區(Buffer)進行操作,數據總是從通道讀取到緩衝區中,或者從緩衝區寫入到通道中。

通道中的數據總是要先讀到一個Buffer,或者總是要從一個Buffer中寫入

緩衝區本質上是一塊可以寫入數據,然後可以從中讀取數據的內存。這塊內存被包裝成NIO Buffer對象

文件讀寫亂碼:編碼、解碼字符集不一致,API使用不當,因爲一箇中文需要兩個字節,InputStream是以字節爲單位讀取,將中文拆成兩個字節分兩次讀取。

注意:在Java NIO中,你可以讓一個線程讀寫多個“channel”。

NIO利用事件模型處理I/O,解決線程池瓶頸處理海量連接,包括利用面向事件的方式編寫服務端/客戶端程序。

非阻塞IO處理連接的線程數和連接數沒有聯繫,當某個連接發送請求到服務器,服務器把這個連接請求當作一個請求"事件",並把這個"事件"分配給相應的函數處理。我們可以把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就可以異步的處理多個事件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章