1. 程式人生 > >java高階特性之IO流

java高階特性之IO流

緩衝流

轉換流

物件流

列印流

標準輸入輸出流

隨機訪問流

陣列流

有關flush():所有的處理流的輸出流,最外層流需要重新整理。

javaIO流

1認識File類

File類的物件表示一個檔案或者一個檔案目錄

絕對路徑:包含碟符的檔案完整路徑

相對路徑:在當前路徑下的檔案路徑

File類中的方法,涉及到檔案或檔案目錄的新建、刪除、獲取檔案的路徑、獲取檔案的大小。並沒有涉及到向檔案中寫入或讀出內容。這樣的讀取或寫入的功能就需要IO流來完成

一般通過將File類的物件作為引數傳遞到流的構造器中,作為流的端點。

檔案的操作

createNewFile():建立file對應的硬碟中的檔案

delete():刪除file物件對應的硬碟中的檔案或檔案目錄

資料夾操作

mkDir() / mkDirs():建立檔案目錄.mkDir()與mkDirs()的方法的區別:當要建立的檔案目錄的上層目錄不存在。此方法放回false,表示建立不成功。而mkDirs()會將不存在的上層檔案目錄一併建立

list():列舉當前檔案目錄下的所有的子File的路徑,String[]

listFiles()列舉當前檔案目錄下的所有的子File. File[]

其他方法:

exists():判斷當前檔案或檔案目錄是否在硬碟上存在

lastModified():最後一次修改的時間

length():獲取檔案內容的大小,單位位元組

renameTo(File newName):file1.renameTo(file2):要想返回值為true,需要保證:file1在硬碟中一定存在;file2在硬碟中一定不存在

canWrite()

canRead()

isFile()

isDirectory()

getName()

getPath()

getAbsoluteFile()

getAbsolutePath()

getParent()

java流的分類

1按照流的流向: 輸入流 vs 輸出流

2 按照處理資料的單位: 位元組流 vs 字元流

3 按照流的角色不同: 節點流(檔案流) vs 處理流

【節點流 直接連線到檔案,而處理流作為節點流與程式的中介。】

二 java 流的框架結構

抽象基類

InputStream OutputStream Reader Writer

節點流(檔案流)

FileInputStream FileOutputStream FileReader FileWriter

緩衝流 (處理流的一種,提高資料傳輸的效率)

BufferedInputStream BufferedOutputSteam

BufferedReader BufferedWriter

以檔案輸入流為例瞭解流的細節步驟:

1建立一個File類的物件,其對映著一個物理檔案。【此時File類物件只是一個普通的物件,可能還沒有物理檔案】

File file = new File(“hello.txt”)

file.createNewFile();

2建立對應的輸入流物件,將如上的File類的物件作為輸入流構造器的引數(要求 :讀入的物理檔案一定存在。),否則報如下異常:

FileNotFoundException

FileInputStream fis = new FileInputStream(file);

3輸入流的實現

byte[] buffer = new byte[10];

int len;//不是buffer.length,而是每次讀入到buffer位元組陣列的位元組數,len = fis.read(buffer)

while((len = fis.read(buffer)) != -1){//read()方法若讀到檔案末尾返回-1

String str = new String(buffer,0,len);

…//

}

4 流的關閉

fis.close();

注:以上只是FileInputStream流的實現步驟,在具體編寫程式碼的時候,由於異常的存在,還需要使用try-catch-finally語句進行處理。

針對於檔案輸出流

1如果輸出流對應的檔案不存在,那麼在輸出的過程中,系統會自動的建立對應的檔案。//此時和輸入流是不一樣的。

2如果輸出流對應的檔案存在,則輸出過程是會對原有的檔案進行覆蓋!注意:不是對檔案內容的覆蓋!

字串型別轉換成字元陣列:

String str = “i love java”; byt e[] buffer = str.getBytes();

字元陣列轉換成字串

String str = new String(buffer,0,buffer.length);

3對於文字檔案(txt)最好使用字元流

對於非文字檔案(doc , jpg ,mp3,mp4 等)使用位元組流

4,針對流,必須手動的關閉。

緩衝流需要注意的情況:

緩衝流需要手動的重新整理,flush()方法

InputStream 和 Reader 是所有輸入流的基類。
InputStream(典型實現:FileInputStream) int read()
int read(byte[] b)
int read(byte[] b, int off, int len)

Reader(典型實現:FileReader)
int read()
int read(char [] c)
int read(char [] c, int off, int len) 程式中開啟的檔案 IO 資源不屬於記憶體裡的資源,垃圾回收機制無法回收該資源,所以應該顯式關閉檔案 IO 資源。

OutputStream 和 Writer 也非常相似: void write(int b/int c); void write(byte[] b/char[] cbuf); void write(byte[] b/char[] buff, int off, int len); void flush(); void close(); 需要先重新整理,再關閉此流因為字元流直接以字元作為操作單位,所以 Writer 可以用字串來替換字元陣列,即以 String 物件作為引數 void write(String str); void write(String str, int off, int len);

緩衝流

為了提高資料讀寫的速度,Java API提供了帶緩衝功能的流類,在使用這些流類時,會建立一個內部緩衝區陣列根據資料操作單位可以把緩衝流分為: BufferedInputStream 和 BufferedOutputStream BufferedReader 和 BufferedWriter緩衝流要“套接”在相應的節點流之上,對讀寫的資料提供了緩衝的功能,提高了讀寫的效率,同時增加了一些新的方法 對於輸出的緩衝流,寫出的資料會先在記憶體中快取,使用flush()將會使記憶體中的資料立刻寫出。

轉換流

轉換流提供了在位元組流和字元流之間的轉換Java API提供了兩個轉換流: InputStreamReader和OutputStreamWriter位元組流中的資料,轉成字元流操作更高效。

InputStreamReader(InputStream is,Stream charset)/

charset可選項,若無,表示預設的本地編碼

charset 表示字符集,用來解碼輸入流中的檔案。用於將位元組流中讀取到的位元組按指定字符集 解碼成字元。需要和InputStream“套接”。構造方法 public InputStreamReader(InputStream in) public InputSreamReader(InputStream in,String charsetName) 如: Reader isr = new InputStreamReader(System.in,”ISO5334_1”);OutputStreamWriter用於將要寫出到字元流中的字元按指定字符集編碼成位元組,編碼過程,需要和OutputStream“套接”。構造方法 public OutputStream Writer (OutputStream out)

public OutputSream Writer (OutputStreamout,StringcharsetName) 此時的charset 表示解碼到檔案。

編碼:字串–>位元組陣列解碼:位元組陣列–>字串 所有的檔案底層都是用位元組形式儲存,讀入的操作屬於解碼,需要InputStreamReader,寫出的操作屬於編碼,需要OutputSteamWriter類。

轉換流的編碼應用 可以將字元按指定編碼格式儲存。 可以對文字資料按指定編碼格式來解讀。 指定編碼表的動作由建構函式完成

與標準輸入輸出流的配合使用:

InputStreamReader reader = new InputStreamReader(System.in);

BufferedReader br = new BufferedReader(reader);

br.readLine();//從鍵盤獲取一個字串,再利用型別轉換獲取其資料如char和int等。

標準輸入輸出流:

System.in和System.out分別代表了系統標準的輸入和輸出裝置預設輸入裝置是鍵盤,輸出裝置是顯示器 System.in的型別是InputStream System.out的型別是PrintStream,PrintSteam是OutputStream的子類

通過System類的setIn,setOut方法對預設裝置進行改變。 public static void setIn(InputStream in) public static void setOut(PrintStream out)Scanner scanner = new Scanner(System.in);

列印流

實現將基本資料型別的資料格式轉化為字串輸出列印流:PrintStream和PrintWriter提供了一系列過載的print和println方法,用於多種資料型別的輸出 PrintStream和PrintWriter的輸出不會丟擲異常 PrintStream和PrintWriter有自動flush功能 System.out返回的是PrintStream的例項

PrintStream stream =

new PrintStream(new FileOutputStream(new File(“hello.txt”)),true);

System.setOut(PrintStream stream);

資料流

為了方便地操作Java語言的基本資料型別的資料,可以使用資料流。資料流有兩個類:(用於讀取和寫出基本資料型別的資料) DataInputStream 和 DataOutputStream分別“套接”在 InputStream 和 OutputStream 節點流上DataInputStream中的方法 boolean readBoolean() byte readByte() char readChar() float readFloat() double readDouble() short readShort() long readLong() int readInt() String readUTF() void readFully(byte[] b)DataOutputStream的方法將上述的方法的read改為相應的write即可。1.作用:儲存或讀取基本資料型別、String、byte[]位元組陣列

2.DataInputStream 和 DataOutputStream

DataInputStream dis =

new DataInputStream(new FileInputStream(new File(“data.dat”)));

DataOutputStream dos =

new DataOutputStream(new FileOutputStream(new File(“data.dat”)));

dos.writeXxx(Xxx xxx); dos.writeUTF(String str);

物件流

ObjectInputStream和OjbectOutputSteam:用於儲存和讀取基本資料型別資料或物件的處理流。它的強大之處就是可以把Java中的物件寫入到資料來源中,也能把物件從資料來源中還原回來。java物件的可序列化機制:

允許把記憶體中的Java物件轉換成平臺無關的二進位制流,從而允許把這種二進位制流持久地儲存在磁碟上,

或通過網路將這種二進位制流傳輸到另一個網路節點。當其它程式獲取了這種二進位制流,就可以恢復成原來的Java物件

序列化:用ObjectOutputStream類儲存基本型別資料或物件的機制 反序列化:用ObjectInputStream類讀取基本型別資料或物件的機制ObjectOutputStream和ObjectInputStream不能序列化

static和transient修飾的成員變數。

當我們使用物件流讀入或者寫出的時候,需要保證物件是序列化的,這是為了保證能把物件寫入到檔案,並能再把物件正確讀回到程式中。java提供的絕大多數類都是序列化的。

如果一個類實現了Serializable 介面,那麼實現該介面的類不需要實現額外的方法。但是該類需要一個私有的靜態的常量long型別。

private static final long serialID = 2233445555L;

java虛擬機器會實現Serializable介面中的方法,按照一定格式的文字將物件寫入到目的地,需要注意的是,使用物件流寫入到檔案時,不僅保證該物件是序列化的,而且該物件的成員物件也必須是序列化的。

利用物件流實現物件的克隆

背景:如果兩個物件有相同的引用,那麼他們就具有相同的實體和功能。

有時候我們想得到物件的一個複製品,該複製品是原物件實體的拷貝,複製品實體的變化不會同步到原物件實體。物件呼叫clone()方法可以獲取物件的複製品,稱為原物件的克隆物件。

物件進行克隆的時候需要注意一點:如果原物件有引用型成員變數,那麼克隆物件的成員變數的引用就與原物件那個成員變數的引用相同,由於引用相同,那麼克隆物件的成員變數的變化就會同步到原物件的成員變數中,程式必須重寫clone()方法,這無疑增大了程式設計的難度。

使用物件流很容易獲取一個序列化物件的克隆,我們只需要將該物件寫入到物件輸出流,然後呼叫物件輸入流讀回物件,得到一個物件的克隆,而且沒有如上的問題。

隨機訪問流

RandomAccessFile 類支援 “隨機訪問” 的方式,程式可以直接跳到檔案的任意地方來讀、寫檔案 支援只訪問檔案的部分內容 可以向已存在的檔案後追加內容理解:

RandomAccessFile ,隨機訪問檔案的行為類似儲存在檔案系統中的一個大型 byte 陣列。存在指向該隱含陣列的游標或索引,稱為檔案指標。

int length();返回檔案的長度

RandomAccessFile 類物件可以自由移動記錄指標: long getFilePointer():獲取檔案記錄指標的當前位置 void seek(long pos):將檔案記錄指標定位到 pos 位置構造器 public RandomAccessFile(File file, String mode) public RandomAccessFile(String name, String mode)建立 RandomAccessFile 類例項需要指定一個 mode 引數,該引數指定 RandomAccessFile 的訪問模式: r: 以只讀方式開啟 rw:開啟以便讀取和寫入 rwd:開啟以便讀取和寫入;同步檔案內容的更新 rws:開啟以便讀取和寫入;同步檔案內容和元資料的更新 public String readLine();讀取文字的下一行,檔案指標先下移,後讀取。不支援完整的Unicode字符集。

public final void wirteUTF(String str) 使用UTF-8的字元編碼將字串寫入檔案。

隨機存取檔案流:RandomAccessFile

  • 1.既可以作為一個輸入流,也可以作為一個輸出流

  • 2.作為一個輸出流,若輸出到的檔案不存在,則會在輸出的過程中建立;若輸出到的檔案已經存在,則是對已存在的檔案的內容的覆蓋

  • 3.實現資料的覆蓋。(檔案指標的概念,從0開始)

陣列流

陣列流的源和目標是計算機記憶體。位元組陣列輸入流ByteArrayInputStream,和位元組陣列輸出流 ByteArrayOutputStream,分別使用計算機記憶體的位元組陣列作為流的源和目標,同樣也有字元陣列的類CharArrayReader和CharArrayWriter。

注:位元組陣列流不會發生IO異常。

以位元組陣列為例分析陣列流:

ByteArrayInputStream(byte[] buf)

ByteArrayInputStream(byte[] buf,int offset,int len);

在構造器引數指明 位元組輸入流的源

從流中讀入的方法:

public int read(),從源中讀入一個位元組,該方法返回位元組值。

public int read(byte[] buf),從源中讀入位元組放到引數buf中,該方法返回實際讀出的位元組個數。若未讀出位元組,返回-1

同理:位元組陣列輸出流 ByteArrayOutputStream(),引數可選int型別的位元組大小,預設為32位元組的緩衝區,可自動擴容。

public void write(int b) 向記憶體緩衝區寫出一個位元組。

public void write(byte[] buf,int off,int len),將引數buf中指定個數的位元組寫出到記憶體緩衝區。

public byte[] toByteArray(),返回輸出流寫入到緩衝區的全部位元組。

可以和物件流配合使用完美實現物件克隆。