1. 程式人生 > 實用技巧 >Java I/O系統(1)

Java I/O系統(1)

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

1、File類

  • File物件呼叫帶不帶引數的list()方法,便可以獲得此File物件包含的全部列表。

  • 獲得一個受限的列表,就要用到“目錄過濾器”。“目錄過濾器”類實現了FilenameFilter介面,FilenameFilter介面很簡單,如下:

    public interface FilenameFilter{

    boolean accept(File dir,String name);

    }

    “目錄過濾器”類存在的唯一原因:將accept()方法提供給list()使用,使list()可以回撥accept(),進而以決定哪些檔案包含在列表中。accept()方法接受一個代表某個特定檔案所在目錄的File物件,以及包含了那個檔名的一個String,記住一點:list()方法會為此目錄物件下的每個檔案呼叫accept(),來判斷該檔案是否包含在內,判斷結果accept()返回的布林值表示。accept()會使用一個正則表示式的matcher物件,來檢視此正則表示式regex是否匹配這個檔案的名字。

  • File物件呼叫listFiles()或listFiles(FilenameFilter filter)產生File陣列。

  • 常用方法:

    建立

    boolean createNewFile():當且僅當不存在具有此抽象路徑名指定名稱的檔案時,不可分地建立一個新的空檔案。

    boolean mkdirs():該方法的作用是建立資料夾,如果當前路徑中包含的父目錄不存在時,也會自動根據需要建立。

    刪除

    boolean delete():刪除此抽象路徑名錶示的檔案或目錄。

    void deleteOnExit():在虛擬機器終止(程式退出)時,請求刪除此抽象路徑名錶示的檔案或目錄。

    判斷

    boolean exists():測試此抽象路徑名錶示的檔案或目錄是否存在。

    boolean isAbsolute():測試此抽象路徑名是否為絕對路徑名。

    boolean isDirectory():測試此抽象路徑名錶示的檔案是否是一個目錄。

boolean isFile():測試此抽象路徑名錶示的檔案是否是一個標準檔案。

boolean isHidden():測試此抽象路徑名指定的檔案是否是一個隱藏檔案。

獲取資訊

StringgetName():返回由此抽象路徑名錶示的檔案或目錄的名稱。

String getPath():將此抽象路徑名轉換為一個路徑名字串。

File getAbsoluteFile():獲取絕對路徑封裝成檔案物件。

String getAbsolutPath():獲取絕對路徑。

String getParent():返回此抽象路徑名父目錄的路徑名字串;如果此路徑名沒有指定父目錄,則返回 null。

long lastModified():返回此抽象路徑名錶示的檔案最後一次被修改的時間。

long length():該方法的作用是返回檔案儲存時佔用的位元組數。該數值獲得的是檔案的實際大小,而不是檔案在儲存時佔用的空間數。

renameTo():該方法的作用是修改檔名。在修改檔名時不能改變檔案路徑,如果該路徑下已有該檔案,則會修改失敗。

boolean setReadOnly():該方法的作用是設定當前檔案或資料夾為只讀。

2、輸入和輸出

  • InputStream型別

    143444_eq4n_570654.png

  • OutputStream型別

    143839_O21L_570654.png

  • 新增屬性和有用的介面

    FilterInputStream和FilterOutputStream是用來提供裝飾器類介面以控制特定輸入流(InputStream)和輸出流(OutputStream)的。FilterInputStream和FilterOutputStream分別自I/O類庫中的基類InputStream和OutputStream派生而來,這兩個類是裝飾器的必要條件。

    FilterInputStream型別

    145014_NLiI_570654.png

    FilterOutputStream型別

    145452_uGSP_570654.png

4、Reader和Writer

  • InputStream和OutputStream在以面向位元組形式的I/O中仍可以提供極有價值的功能,Reader和Writer則提供相容Unicode與面向字元的I/O功能。設計Reader和Writer繼承層次結構主要是為了國際化,Unicode用於字元國際化,老的I/O流繼承層次結構僅支援8位位元組流,並不能很好地處理16位的Unicode字元。

  • 有時必須把來自於“位元組”層次結構中的類和“字元”層次結構中的類結合起來使用。為了實現這個目的,要用到“介面卡(adapter)”類:InputStreamReader可把InputStream轉換為Reader,而OutputStreamWriter可把OutputStream轉換為Writer。

  • 有時面向位元組的InputStream和OutputStream才是正確的解決方案,特別是java.util.zip類庫就是面向位元組的而不是面向字元的。最明智的做法是儘量嘗試使用Reader和Writer,一旦程式程式碼無法成功編譯,就不得不使用面向位元組的類庫。

  • 資訊來源和去處

    165923_j1Lf_570654.png

  • 更改流的行為

    170440_zGBw_570654.jpg

    注:無論何時使用readLine(),都不應該使用DataInputStream,而應該使用BufferedReader。除了這一點,DataInputStream仍是I/O類庫的首選成員。

  • 未發生變化的類

    171203_MZJ4_570654.png

  • 注:對於儲存和檢索可傳輸格式的資料,可以使用InputStream和OutputStream繼承層次結構。

5、自我獨立的類:RandomAccessFile

  • RandomAccessFile適用於由已知大小的記錄組成的檔案,所以可使用seek()將記錄從一處移到另一處,然後讀取或修改記錄。檔案中記錄的大小不一定相同,只要能夠確定那些記錄的大小以及它們在檔案中的位置即可。

  • RandomAccessFile不是InputStream或OutputStream繼承層次結構中的一部分,除了實現DataInput和DataOutput之外,它和這兩個繼承層次結構沒有任何關聯。

  • RandomAccessFile的工作方式類似於把DataInputStream和DataOutputStream組合起來使用,還添加了一些方法。其中方法getFilePointer()用於查詢當前所處的檔案位置,seek()用於在檔案內移至新的位置,length()用於判斷檔案的最大尺寸。另外,其構造器還需要第二個引數用來指示只是“隨機讀”(r)還是“既讀又寫”(rw)。

  • 只有RandomAccessFile支援搜尋方法,並且只適用於檔案。

  • RandomAccessFile的大多數功能由nio儲存對映檔案所取代。

6、I/O流的典型使用方式

  • 緩衝輸入檔案。開啟一個檔案用於字元輸入,可使用以String或File物件作為檔名的FileReader。為了提高速度,希望對那個檔案進行緩衝,那將所產生的引用傳遞給一個BufferedReader構造器。由於BufferedReader也提供readLine()方法,這就是最終物件和進行讀取的介面。

  • 格式化的記憶體輸入。要讀取格式化資料,可使用DataInputStream,它是一個面向位元組的I/O類。提供位元組陣列所產生的ByteArrayInputStream是一個適合傳遞給DataInputStream的InputStream。從DataInputStream用readByte()一次一個位元組地讀取字元,那麼任何位元組的值都是合法的結果,因此返回值不能用來檢測輸入是否結束。但是,可以使用available()方法檢視還有多少可供存取的字元。

  • 基本的檔案輸出。FileWriter物件可以向檔案寫入資料,首先建立一個與指定檔案連線的FileWriter,通常BufferedWriter將其包裝起來用以緩衝輸出。另外如果想提供格式化機制,它可被裝飾成PrintWriter。按這種方式建立的資料檔案可作為普通文字檔案讀取。

  • 儲存和恢復資料。PrintWriter可以對資料進行格式化,以便人們的閱讀。但為了輸出可供另外一個流恢復資料,需要用DataOutputStream寫入資料,並用DataInputStream恢復資料。當使用DataOutputStream時,寫字串並讓DataInputStream能夠恢復它的唯一可靠做法是使用UTF-8編碼,可以使用writeUTF()和readUTF()來實現。

  • 讀寫隨機訪問檔案。使用RandomAccessFile,類似於組合使用DataInputStream和DataOutputStream,另外利用seek()可以在檔案中到處移動,並修改檔案中的某個值。RandomAccessFile擁有讀取基本型別和UTF-8字串的各種具體方法。可能會考慮使用“記憶體對映檔案”來替代RandomAccessFile。

  • 管道流。PipedInputStream、PipedOutputStream、PipedReader及PipedWriter,它們的價值只有在開始理解多執行緒之後才會顯現,因為管道流用於任務間的通訊。

7、標準I/O

  • 從標準輸入中讀取。按照標準I/O模型,java提供各類System.in、System.out和System.err。其中System.out已事先被包裝成PrintStream物件,System.err同樣是PrintStream,但System.in卻是一個沒有包裝過的未經加工的InputStream。這意味著可以立即使用System.out和System.err,但是在讀取System.in之前必須對其進行包裝。譬如,new BufferedReader(new InputStreamReader (System.in));

  • 將System.out轉換成PrintWriter。System.out是一個PrintStream,而PrintStream是一個OutputStream,PrintWriter有一個可接受OutputStream作為引數的構造器,另外一個引數設為true,開啟自動清空功能,否則看不到輸出。

  • Java的System類提供了一些簡單的靜態方法呼叫,以允許對標準輸入、輸出和錯誤I/O流進行重定向:setIn(InputStream)、setOut(PrintStream)、setErr(PrintStream)。I/O重定向操縱的是位元組流,而不是字元流。

8、新的I/O

  • Java.nio.*包中引入新的Java I/O類庫,其目的在於提高速度。速度的提高來自於所使用的結構更接近於作業系統執行I/O的方式:通道(channels)和緩衝器(buffers)。我們並沒有直接和通道互動,只是和緩衝器互動,並把緩衝器派送到通道,通道要麼從緩衝器獲得資料,要麼向緩衝器傳送資料。

  • 唯一直接與通道互動的緩衝器是ByteBuffer——可以儲存未加工位元組的緩衝器。ByteBuffer是相當基礎的類:通過告知分配多少儲存空間來建立一個ByteBuffer物件,並還有一個方法選擇集,用於以原始的位元組形式或基本資料型別輸出和讀取資料。但,沒辦法輸出或讀取物件,即使是字串物件也不行。

  • 舊I/O類庫中有三個類被修改,用以產生FileChannel(getChannel()方法)。這三個類是FileInputStream、FileOutputStream以及用於既讀又寫的RandomAccessFile,注意這些是位元組操縱流。Reader和Writer不能用於產生通道,但java.nio.channels.Channels類提供了實用方法,用以在通道中產生Reader和Writer。

  • 通道是一種相當基礎的東西:可以向它傳送用於讀寫的ByteBuffer,並可以鎖定檔案的某些區域用於獨佔式訪問。

  • 將位元組放於ByteBuffer的方法:一種是put()方法對它們進行填充,填入一個或多個位元組,或基本資料型別的值;一種是使用wrap()方法將已存在的位元組陣列“包裝”到ByteBuffer中。

  • 可以在檔案內隨處移動FileChannel,用到方法position()。

  • 對於只讀訪問,必須顯式地使用靜態方法allocate()來分配ByteBuffer。nio的目標是快速移動大量資料,因此ByteBuffer的大小就顯得尤為重要。達到更高的速度也可能是使用方法allocateDirect()而不是allocate(),以產生一個與作業系統有更高耦合性的直接緩衝器,但這種分配開支會更大,並且具體實現也隨作業系統的不同而不同。

  • 一旦呼叫read()來告知FileChannel向ByteBuffer儲存位元組,就必須呼叫緩衝器上的flip()方法,讓它做好讓別人讀取位元組(write())的準備。如果打算使用緩衝器執行進一步的read()操作,必須得呼叫clear()來為每個read()做好準備。

  • 特殊方法transferTo()和transferFrom()允許講一個通道和另一個通道直接相連。

  • 儘管ByteBuffer只能儲存位元組型別的資料,但是它具有可以從其所容納的位元組中產生各種不同基本資料型別的方法。向ByteBuffer插入基本資料型別的最簡單方法是:利用asCharBuffer()、asShortBuffer()等獲得該緩衝上的檢視,然後使用檢視的put()方法。注意使用ShortBuffer檢視的put()方法時,需要進行型別轉換。

  • 檢視緩衝器可以讓我們通過某個特定的基本資料型別的視窗檢視其底層的ByteBuffer。ByteBuffer依然是實際儲存資料的地方,支援著前面的檢視,因此對檢視的任何修改都會對映成為對ByteBuffer中資料的修改。

  • 位元組存放次序。“big endian”(高位優先)將最重要的位元組存放在地址最低的儲存單元,而“little endian”(低位優先)則是將最重要的位元組放在地址最高的儲存器單元。ByteBuffer是以高位優先的形式儲存資料的,並且資料在網上傳送時也常常使用高位優先的形式。可以使用帶有引數ByteOrder.BIG_ENDIAN和ByteOrder.LITTLE_ENDIAN的order()方法改變ByteBuffer的位元組排序方式。如果以short(ByteBuffer.asShortBuffer())形式讀取資料得到的數字是97(二進位制形式為00000000 01100001),但如果將ByteBuffer更改為低位優先形式,仍以short形式讀取資料,得到的數字確是24832(二進位制形式為01100001 00000000)。array()方法顯示檢視底層位元組,該方法是可選的,只能對由陣列支援的緩衝器呼叫此方法。

  • 緩衝器操縱資料

    173033_eeOw_570654.png

  • 緩衝器的細節。Buffer由資料和可以高效地訪問及操作這些資料的四個索引組成,這三個索引是:mark(標記)、position(位置)、limit(界限)和capacity(容量)。

    175500_KC4r_570654.png

    reset()方法把position的值設定為mark的值;

    rewind()方法把position設定到緩衝器的開始位置。

轉載於:https://my.oschina.net/90liusq/blog/370354