Java基礎-io體系總結

簡介

無論是系統、還是語言的設計中IO的設計都是異常複雜的。面臨的最大的挑戰一般是如何覆蓋所有可能的因素,我們不僅僅要考慮文件、控制檯、網絡、內存等不同的種類,而且要處理大量的不同的讀取方式,如:順序讀取、隨機讀取,二進制讀取、字符讀取,按行讀取、按字符讀取……
Java語言在IO設計方面取得較大的成功,它是完全面向對象的,主要採用裝飾器模式避免大量的類,包括了最大的可能性,提供了較好的擴展機制……
“Java庫的設計者通過創建大量類來攻克這個難題。事實上,Java的IO系統採用瞭如此多的類,以致剛開始會產生不知從何處入手的感覺(具有諷刺意味的是,Java的IO設計初衷實際要求避免過多的類)。” 上面一段來自《Think in Java》,確實很多初學者剛剛學習java的IO時會比較茫然,不過等我們知道裝飾器模式(Decorator)的用意、場景及其在Java的IO包中的使用,你可能會真正領會整個IO的FrameWork。

io的分類

Java IO一般包含兩個部分:1.java.io包中堵塞型IO;2.java.nio包中的非堵塞型IO,通常稱爲New IO。學過操作系統的朋友都知道系統運行的瓶頸一般在於IO操作,一般打開某個IO通道需要大量的時間,同時端口中不一定就有足夠的數據,這樣read方法就一直等待讀取此端口的內容,從而浪費大量的系統資源。有人也許會提出使用java的多線程技術啊!但是在當前進程中創建線程也是要花費一定的時間和系統資源的,因此不一定可取。Java New IO的非堵塞技術主要採用了Observer模式,就是有一個具體的觀察者和=監測IO端口,如果有數據進入就會立即通知相應的應用程序。這樣我們就避免建立多個線程,同時也避免了read等待的時間。不過本篇主要講述java的堵塞型IO,就是我們通常應用的那個包。
打開你的java.io包你可以看到Java的IO包含大量的類和接口(JDK1.6中包含83個類或者接口),如此衆多的類和接口似乎無從下手。下面就將IO簡單地分類。Java的IO主要包含三個部分:1.流式部分――IO的主體部分;2.非流式部分――主要包含一些輔助流式部分的類,如:File類、RandomAccessFile類和FileDescriptor等類;3.文件讀取部分的與安全相關的類,如:SerializablePermission類。以及與本地操作系統相關的文件系統的類,如:FileSystem類和Win32FileSystem類和WinNTFileSystem類。
流式部分可以概括爲:兩個對應一個橋樑。兩個對應指:1.字節流(Byte Stream)和字符流(Char Stream)的對應;2.輸入和輸出的對應。一個橋樑指:從字節流到字符流的橋樑。對應於輸入和輸出爲InputStreamReader和OutputStreamWriter。

字節流、字符流

字節流
系統中的文件(圖片、視頻等)都是以二進制進行存儲,所以最小數據單元就是字節(8個二進制字符),這也意味着系統中的所有文件都可以用字節流進行處理。即字節流讀數據時,一次讀8位。

字符流
有字節流了,爲什麼還要使用字符流呢?因爲每個國家的字符不同,這涉及到了字符編碼問題。比如漢字,獲取到漢字字節數據的同時,指定編碼表纔可以解析正確的數據。只要操作字符數據,優先考慮字符流體系。

分類 字節輸入流 字節輸出流 字符輸入流 字符輸出流
抽象基類 InputStream OutputStream Reader Writer
訪問文件 FileInputStream FileOutputStream FileReader FileWriter
訪問數組 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
訪問管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
訪問字符串 StringReader StringWriter
緩衝流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
轉換流 InputStreamReader OutputStreamWriter
對象流 ObjectInputStream ObjectOutputStream
抽象基類 FilterInputStream FilterOutputStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回輸入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

抽象基類

InputStream/Reader: 所有的輸入流的基類,前者是字節輸入流,後者是字符輸入流。
OutputStream/Writer: 所有輸出流的基類,前者是字節輸出流,後者是字符輸出流。

對於InputStream和Reader而言,它們把輸入設備抽象成爲一個”水管“,這個水管的每個“水滴”依次排列,如圖15.5所示:
    從圖15.5可以看出,字節流和字符流的處理方式其實很相似,只是它們處理的輸入/輸出單位不同而已。輸入流使用隱式的記錄指針來表示當前正準備從哪個“水滴”開始讀取,每當程序從InputStream或者Reader裏面取出一個或者多個“水滴”後,記錄指針自定向後移動;除此之外,InputStream和Reader裏面都提供了一些方法來控制記錄指針的移動。
在這裏插入圖片描述
   對於OutputStream和Writer而言,它們同樣把輸出設備抽象成一個”水管“,只是這個水管裏面沒有任何水滴,如圖15.6所示:

正如圖15.6所示,當執行輸出時,程序相當於依次把“水滴”放入到輸出流的水管中,輸出流同樣採用隱示指針來標識當前水滴即將放入的位置,每當程序向OutputStream或者Writer裏面輸出一個或者多個水滴後,記錄指針自動向後移動。
在這裏插入圖片描述
 圖15.5和圖15.6顯示了java Io的基本概念模型,除此之外,Java的處理流模型則體現了Java輸入和輸出流設計的靈活性。處理流的功能主要體現在以下兩個方面。
性能的提高:主要以增加緩衝的方式來提供輸入和輸出的效率。
操作的便捷:處理流可能提供了一系列便捷的方法來一次輸入和輸出大批量的內容,而不是輸入/輸出一個或者多個“水滴”。

處理流可以“嫁接”在任何已存在的流的基礎之上,這就允許Java應用程序採用相同的代碼,透明的方式來訪問不同的輸入和輸出設備的數據流。圖15.7顯示了處理流的模型。

字節流的繼承圖

在這裏插入圖片描述
1.InputStream是所有的輸入字節流的父類,它是一個抽象類。
2. ByteArrayInputStream、StringBufferInputStream、FileInputStream是三種基本的介質流,它們分別將Byte數組、StringBuffer、和本地文件中讀取數據。PipedInputStream是從與其它線程共用的管道中讀取數據
在這裏插入圖片描述
在這裏插入圖片描述

節流的繼承圖

在這裏插入圖片描述
在上面的關係圖中可以看出:1.OutputStream是所有的輸出字節流的父類,它是一個抽象類。2. ByteArrayOutputStream、FileOutputStream是兩種基本的介質流,它們分別向Byte數組、和本地文件中寫入數據。PipedOutputStream是向與其它線程共用的管道中寫入數據, 3. ObjectOutputStream和所有FilterOutputStream的子類都是裝飾流。下表列出了輸出字節流的功能及如何使用它們。
在這裏插入圖片描述
在這裏插入圖片描述

字節流的輸入與輸出的對應

在這裏插入圖片描述
上圖中藍色的爲主要的對應部分,紅色的部分就是不對應部分。我習慣上稱之爲“不入流”部分。紫色的虛線部分代表這些流一般要搭配使用。從上面的圖中可以看出Java IO中的字節流是極其對稱的。
“存在及合理”我們看看這些字節流中不太對稱的幾個類吧!
1.LineNumberInputStream主要完成從流中讀取數據時,會得到相應的行號,至於什麼時候分行、在哪裏分行是由改類主動確定的,並不是在原始中有這樣一個行號。在輸出部分沒有對應的部分,我們完全可以自己建立一個LineNumberOutputStream,在最初寫入時會有一個基準的行號,以後每次遇到換行時會在下一行添加一個行號,看起來也是可以的。好像更不入流了。
2. PushbackInputStream的功能是查看最後一個字節,不滿意就放入緩衝區。主要用在編譯器的語法、詞法分析部分。輸出部分的BufferedOutputStream幾乎實現相近的功能。
3. StringBufferInputStream已經被Deprecated,本身就不應該出現在InputStream部分,主要因爲String應該屬於字符流的範圍。已經被廢棄了,當然輸出部分也沒有必要需要它了!還允許它存在只是爲了保持版本的向下兼容而已。
4. SequenceInputStream可以認爲是一個工具類,將兩個或者多個輸入流當成一個輸入流依次讀取。完全可以從IO包中去除,還完全不影響IO包的結構,卻讓其更“純潔”――純潔的Decorator模式。
5. PrintStream也可以認爲是一個輔助工具。主要可以向其他輸出流,或者FileInputStream寫入數據,本身內部實現還是帶緩衝的。本質上是對其它流的綜合運用的一個工具而已。一樣可以踢出IO包!System.out和System.out就是PrintStream的實例!
藍色的部分是IO字節流的主要組成部分,存在極強的對稱關係。關於搭配使用的三對類補充一下:ObjectInputStream/ObjectOutputStream和DataInputStream/DataOutputStream主要是要求寫對象/數據和讀對象/數據的次序要保持一致,否則輕則不能得到正確的數據,重則拋出異常(一般會如此);PipedInputStream/PipedOutputStream在創建時一般就一起創建,調用它們的讀寫方法時會檢查對方是否存在,或者關閉!道理極其簡單――對方都不在了,怎麼交互啊!

InputStream

int read()
從輸入流中讀取數據的下一個字節。 返回 0 到 255 範圍內的 int 字節值。 如果因爲已經到達流末尾而沒有可用的字節, 則返回值 -1。
int read(byte[] b)
從此輸入流中將最多 b.length 個字節的數據讀入一個 byte 數組中。 如果因爲已經到達流末尾而沒有可用的字節, 則返回值 -1。 否則以整數形式返回實際讀取的字節數。
int read(byte[] b, int off,int len)
將輸入流中最多 len 個數據字節讀入 byte 數組。 嘗試讀取 len 個字節, 但讀取的字節也可能小於該值。 以整數形式返回實際讀取的字節數。 如果因爲流位於文件末尾而沒有可用的字節, 則返回值 -1。
public void close() throws IOException
關閉此輸入流並釋放與該流關聯的所有系統資源。

Reader

int read()
讀取單個字符。 作爲整數讀取的字符, 範圍在 0 到 65535 之間 (0x00-0xffff)(2個字節的Unicode碼) , 如果已到達流的末尾, 則返回 -1
int read(char[] cbuf)
將字符讀入數組。 如果已到達流的末尾, 則返回 -1。 否則返回本次讀取的字符數。
int read(char[] cbuf,int off,int len)
將字符讀入數組的某一部分。 存到數組cbuf中, 從off處開始存儲, 最多讀len個字符。 如果已到達流的末尾, 則返回 -1。 否則返回本次讀取的字符數。
public void close() throws IOException
關閉此輸入流並釋放與該流關聯的所有系統資源。

OutputStream & Writer

 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);
 FileOutputStream 從文件系統中的某個文件中獲得輸出字節。 FileOutputStream用於寫出非文本數據之類的原始字節流。 要寫出字符流, 需要使用 FileWriter

OutputStream

 void write(int b)
將指定的字節寫入此輸出流。 write 的常規協定是:向輸出流寫入一個字節。 要寫入的字節是參數 b 的八個低位。 b 的 24 個高位將被忽略。 即寫入0~255範圍的。
 void write(byte[] b)
將 b.length 個字節從指定的 byte 數組寫入此輸出流。 write(b) 的常規協定是:應該與調用 write(b, 0, b.length) 的效果完全相同。
 void write(byte[] b,int off,int len)
將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流。
 public void flush()throws IOException
刷新此輸出流並強制寫出所有緩衝的輸出字節, 調用此方法指示應將這些字節立即寫入它們預期的目標。
 public void close() throws IOException
關閉此輸出流並釋放與該流關聯的所有系統資源。

Writer

 void write(int c)
寫入單個字符。 要寫入的字符包含在給定整數值的 16 個低位中, 16 高位被忽略。 即寫入0 到 65535 之間的Unicode碼。
 void write(char[] cbuf)
寫入字符數組。
 void write(char[] cbuf,int off,int len)
寫入字符數組的某一部分。 從off開始, 寫入len個字符
 void write(String str)
寫入字符串。
 void write(String str,int off,int len)
寫入字符串的某一部分。
 void flush()
刷新該流的緩衝, 則立即將它們寫入預期目標。
 public void close() throws IOException
關閉此輸出流並釋放與該流關聯的所有系統資源。

節點流(或文件流)讀取文件

1.建立一個流對象,將已存在的一個文件加載進流。
 FileReader fr = new FileReader(new File(“Test.txt”));
2.創建一個臨時存放數據的數組。
 char[] ch = new char[1024];
3.調用流對象的讀取方法將流中的數據讀入到數組中。
 fr.read(ch);
4. 關閉資源。
 fr.close();


FileReader fr = null;
try {
	fr = new FileReader(new File("c:\\test.txt"));
	char[] buf = new char[1024];
	int len;
	while ((len = fr.read(buf)) != -1) {
		System.out.print(new String(buf, 0, len));
	}
} catch (IOException e) {
	System.out.println("read-Exception :" + e.getMessage());
} finally {
	if (fr != null) {
	try {
		fr.close();
	} catch (IOException e) {
	System.out.println("close-Exception :" + e.getMessage());
	}
}

節點流(或文件流)寫入文件

1.創建流對象,建立數據存放文件
 FileWriter fw = new FileWriter(new File(“Test.txt”));
2.調用流對象的寫入方法,將數據寫入流
 fw.write(“atguigu-songhongkang”);
3.關閉流資源,並將流中的數據清空到文件中。
 fw.close();

FileWriter fw = null;
try {
	fw = new FileWriter(new File("Test.txt"));
	fw.write("atguigu-songhongkang");
} catch (IOException e) {
	e.printStackTrace();
} finally {
	if (fw != null)
	try {
		fw.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

節點流(或文件流) 定義文件路徑時,注意:可以用“/”或者“\”。
 在寫入一個文件時,如果使用構造器FileOutputStream(file),則目錄下有同名文件將被覆蓋。
 如果使用構造器FileOutputStream(file,true),則目錄下的同名文件不會被覆蓋,在文件內容末尾追加內容。
 在讀取文件時,必須保證該文件已存在,否則報異常。
 字節流操作字節,比如: .mp3, .avi, .rmvb, mp4, .jpg, .doc, .ppt
 字符流操作字符,只能操作普通文本文件。 最常見的文本文件: .txt, .java, .c, .cpp 等語言的源代碼。尤其注意.doc,excel,ppt這些不是文本文件。

緩衝流

 爲了提高數據讀寫的速度, Java API提供了帶緩衝功能的流類,在使用這些流類時,會創建一個內部緩衝區數組,缺省使用8192個字節(8Kb)的緩衝區。
 緩衝流要“套接”在相應的節點流之上,根據數據操作單位可以把緩衝流分爲:
BufferedInputStream 和 BufferedOutputStream
BufferedReader 和 BufferedWriter 當讀取數據時,數據按塊讀入緩衝區,其後的讀操作則直接訪問緩衝區
 當使用BufferedInputStream讀取字節文件時, BufferedInputStream會一次性從文件中讀取8192個(8Kb), 存在緩衝區中, 直到緩衝區裝滿了, 才重新從文件中讀取下一個8192個字節數組。
 向流中寫入字節時, 不會直接寫到文件, 先寫到緩衝區中直到緩衝區寫滿,BufferedOutputStream纔會把緩衝區中的數據一次性寫到文件裏。使用方法flush()可以強制將緩衝區的內容全部寫入輸出流
 關閉流的順序和打開流的順序相反。只要關閉最外層流即可, 關閉最外層流也會相應關閉內層節點流
 flush()方法的使用:手動將buffer中內容寫入文件 如果是帶緩衝區的流對象的close()方法, 不但會關閉流, 還會在關閉流之前刷
新緩衝區, 關閉後不能再寫出

BufferedReader br = null;
BufferedWriter bw = null;
try {
	// 創建緩衝流對象:它是處理流,是對節點流的包裝
	br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt"));
	bw = new BufferedWriter(new FileWriter("d:\\IOTest\\dest.txt"));
	String str;
	while ((str = br.readLine()) != null) { // 一次讀取字符文本文件的一行字符
		bw.write(str); // 一次寫入一行字符串
		bw.newLine(); // 寫入行分隔符
	}
	bw.flush(); // 刷新緩衝區
} catch (IOException e) {
	e.printStackTrace();
} finally {
bw.close(); // 關閉過濾流時,會自動關閉它所包裝的底層節點流
br.close();
}

轉換流

轉換流提供了在字節流和字符流之間的轉換
Java API提供了兩個轉換流:
 InputStreamReader:將InputStream轉換爲Reader
 OutputStreamWriter:將Writer轉換爲OutputStream
 字節流中的數據都是字符時,轉成字符流操作更高效。
 很多時候我們使用轉換流來處理文件亂碼問題。實現編碼和解碼的功能。

InputStreamReader

 實現將字節的輸入流按指定字符集轉換爲字符的輸入流。
 需要和InputStream“套接”。
 構造器
 public InputStreamReader(InputStream in)
 public InputSreamReader(InputStream in,String charsetName)
如: Reader isr = new InputStreamReader(System.in,”gbk”);指定字符集

OutputStreamWriter

 實現將字符的輸出流按指定字符集轉換爲字節的輸出流。
 需要和OutputStream“套接”。
 構造器
 public OutputStreamWriter(OutputStream out)
 public OutputSreamWriter(OutputStream out,String charsetName)

public void testMyInput() throws Exception {
	FileInputStream fis = new FileInputStream("dbcp.txt");
	FileOutputStream fos = new FileOutputStream("dbcp5.txt");
	InputStreamReader isr = new InputStreamReader(fis, "GBK");
	OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
	BufferedReader br = new BufferedReader(isr);
	BufferedWriter bw = new BufferedWriter(osw);
	String str = null;
	while ((str = br.readLine()) != null) {
		bw.write(str);
		bw.newLine();
		bw.flush();
	}
	bw.close();
	br.close();
	}

打印流

實現將基本數據類型的數據格式轉化爲字符串輸出
打印流: PrintStream和PrintWriter
 提供了一系列重載的print()和println()方法,用於多種數據類型的輸出
 PrintStream和PrintWriter的輸出不會拋出IOException異常
 PrintStream和PrintWriter有自動flush功能
 PrintStream 打印的所有字符都使用平臺的默認字符編碼轉換爲字節。在需要寫入字符而不是寫入字節的情況下,應該使用 PrintWriter 類。
 System.out返回的是PrintStream的實例

PrintStream ps = null;
try {
	FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
	// 創建打印輸出流,設置爲自動刷新模式(寫入換行符或字節 '\n' 時都會刷新輸出緩衝區)
	ps = new PrintStream(fos, true);
	if (ps != null) {// 把標準輸出流(控制檯輸出)改成文件
		System.setOut(ps);
	}
	for (int i = 0; i <= 255; i++) { // 輸出ASCII字符
	System.out.print((char) i);
	if (i % 50 == 0) { // 每50個數據一行
		System.out.println(); // 換行
	}
}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} finally {
	if (ps != null) {
		ps.close();
	}
}

數據流

 爲了方便地操作Java語言的基本數據類型和String的數據,可以使用數據流。
 數據流有兩個類: (用於讀取和寫出基本數據類型、 String類的數據)
 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即可。

對象流

 ObjectInputStream和OjbectOutputSteam
 用於存儲和讀取基本數據類型數據或對象的處理流。它的強大之處就是可以把Java中的對象寫入到數據源中,也能把對象從數據源中還原回來。
 序列化: 用ObjectOutputStream類保存基本類型數據或對象的機制
 反序列化: 用ObjectInputStream類讀取基本類型數據或對象的機制
 ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量
對象序列化機制允許把內存中的Java對象轉換成平臺無關的二進制流,從而允許把這種二進制流持久地保存在磁盤上,或通過網絡將這種二進制流傳輸到另一個網絡節點。 //當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象
序列化的好處在於可將任何實現了Serializable接口的對象轉化爲字節數據,使其在保存和傳輸時可被還原
序列化是 RMI(Remote Method Invoke – 遠程方法調用)過程的參數和返回值都必須實現的機制,而 RMI 是 JavaEE 的基礎。因此序列化機制是JavaEE 平臺的基礎
如果需要讓某個對象支持序列化機制,則必須讓對象所屬的類及其屬性是可序列化的,爲了讓某個類是可序列化的,該類必須實現如下兩個接口之一。否則,會拋出NotSerializableException異常
Serializable
Externalizable
凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量:
private static final long serialVersionUID;
serialVersionUID用來表明類的不同版本間的兼容性。 簡言之,其目的是以序列化對象進行版本控制,有關各版本反序列化時是否兼容。
如果類沒有顯示定義這個靜態常量,它的值是Java運行時環境根據類的內部細節自動生成的。 若類的實例變量做了修改, serialVersionUID 可能發生變化。 故建議,顯式聲明。
 簡單來說, Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時, JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。 (InvalidCastException)

對象的序列化使用對象流序列化對象
若某個類實現了 Serializable 接口,該類的對象就是可序列化的:
創建一個 ObjectOutputStream
調用 ObjectOutputStream 對象的 writeObject(對象) 方法輸出可序列化對象
注意寫出一次,操作flush()一次
反序列化
創建一個 ObjectInputStream
調用 readObject() 方法讀取流中的對象
強調: 如果某個類的屬性不是基本數據類型或 String 類型,而是另一個
引用類型,那麼這個引用類型必須是可序列化的,否則擁有該類型的Field 的類也不能序列化將對象寫入到磁盤或者進行網絡傳輸。
//要求對象必須實現序列化
//反序列化:將磁盤中的對象數據源讀出。

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person(“韓梅梅”, 18, “中華大街”, new Pet());
oos.writeObject§;
oos.flush();
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();

談談你對java.io.Serializable接口的理解,我們知道它用於序列化,是空方法接口,還有其它認識嗎?
 實現了Serializable接口的對象,可將它們轉換成一系列字節,並可在以後完全恢復回原來的樣子。 這一過程亦可通過網絡進行。這意味着序列化機制能自動補償操作系統間的差異。 換句話說,可以先在Windows機器上創建一個對象,對其序列化,然後通過網絡發給一臺Unix機器,然後在那裏準確無誤地重新“裝配”。不必關心數據在不同機器上如何表示,也不必關心字節的順序或者其他任何細節。
 由於大部分作爲參數的類如String、 Integer等都實現了java.io.Serializable的接口,也可以利用多態的性質,作爲參數使接口更靈活。

隨機存取文件流RandomAccessFile 類

RandomAccessFile 聲明在java.io包下,但直接繼承於java.lang.Object類。 並且它實現了DataInput、 DataOutput這兩個接口,也就意味着這個類既可以讀也可以寫。
RandomAccessFile 類支持 “隨機訪問” 的方式,程序可以直接跳到文件的任意地方來讀、寫文件
支持只訪問文件的部分內容
可以向已存在的文件後追加內容
RandomAccessFile 對象包含一個記錄指針,用以標示當前讀寫處的位置。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:打開以便讀取和寫入; 同步文件內容和元數據的更新
 如果模式爲只讀r。則不會創建文件,而是會去讀取一個已經存在的文件,如果讀取的文件不存在則會出現異常。 如果模式爲rw讀寫。如果文件不存在則會去創建文件,如果存在則不會創建。

我們可以用RandomAccessFile這個類,來實現一個多線程斷點下載的功能,用過下載工具的朋友們都知道,下載前都會建立兩個臨時文件,一個是與被下載文件大小相同的空文件,另一個是記錄文件指針的位置文件,每次暫停的時候,都會保存上一次的指針,然後斷點下載的時候,會繼續從上一次的地方下載,從而實現斷點下載或上傳的功能,有興趣的朋友們可以自己實現下。讀取文件內容

流的基本應用小節
 流是用來處理數據的。
 處理數據時,一定要先明確數據源,與數據目的地
 數據源可以是文件,可以是鍵盤。
 數據目的地可以是文件、顯示器或者其他設備。
 而流只是在幫助數據進行傳輸,並對傳輸的數據進行處理,比如過濾處理、轉換處理等。

13-11 NIO.2中Path、
Paths、 Files類的使用Java NIO 概述
 Java NIO (New IO, Non-Blocking IO)是從Java 1.4版本開始引入的一套新的IO API,可以替代標準的Java IO API。 NIO與原來的IO有同樣的作用和目的,但是使用的方式完全不同, NIO支持面向緩衝區的(IO是面向流的)、基於通道的IO操作。 NIO將以更加高效的方式進行文件的讀寫操作。
 Java API中提供了兩套NIO, 一套是針對標準輸入輸出NIO, 另一套就是網絡編程NIO。
|-----java.nio.channels.Channel
|-----FileChannel:處理本地文件
|-----SocketChannel: TCP網絡編程的客戶端的Channel
|-----ServerSocketChannel:TCP網絡編程的服務器端的Channel
|-----DatagramChannel: UDP網絡編程中發送端和接收端的Channel

13-11 NIO.2中Path、 Paths、 Files類的使用NIO. 2
 隨着 JDK 7 的發佈, Java對NIO進行了極大的擴展,增強了對文件處理和文件系統特性的支持,以至於我們稱他們爲 NIO.2。因爲 NIO 提供的一些功能, NIO已經成爲文件處理中越來越重要的部分。

13-11 NIO.2中Path、 Paths、 Files類的使用Path、 Paths和Files核心API
 早期的Java只提供了一個File類來訪問文件系統,但File類的功能比較有限,所提供的方法性能也不高。而且, 大多數方法在出錯時僅返回失敗,並不會提供異常信息。
 NIO. 2爲了彌補這種不足,引入了Path接口,代表一個平臺無關的平臺路徑,描述了目錄結構中文件的位置。 Path可以看成是File類的升級版本,實際引用的資源也可以不存在。
 在以前IO操作都是這樣寫的:
import java.io.File;
File file = new File(“index.html”);
 但在Java7 中,我們可以這樣寫:
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get(“index.html”);

13-11 NIO.2中Path、 Paths、 Files類的使用Path、 Paths和Files核心API 同時, NIO.2在java.nio.file包下還提供了Files、 Paths工具類, Files包含了大量靜態的工具方法來操作文件; Paths則包含了兩個返回Path的靜態工廠方法。
 Paths 類提供的靜態 get() 方法用來獲取 Path 對象:
static Path get(String first, String … more) : 用於將多個字符串串連成路徑
static Path get(URI uri): 返回指定uri對應的Path路徑

13-11 NIO.2中Path、 Paths、 Files類的使用Path接口
 Path 常用方法:
 String toString() : 返回調用 Path 對象的字符串表示形式
 boolean startsWith(String path) : 判斷是否以 path 路徑開始
 boolean endsWith(String path) : 判斷是否以 path 路徑結束
 boolean isAbsolute() : 判斷是否是絕對路徑
 Path getParent() :返回Path對象包含整個路徑,不包含 Path 對象指定的文件路徑
 Path getRoot() :返回調用 Path 對象的根路徑
 Path getFileName() : 返回與調用 Path 對象關聯的文件名
 int getNameCount() : 返回Path 根目錄後面元素的數量
 Path getName(int idx) : 返回指定索引位置 idx 的路徑名稱
 Path toAbsolutePath() : 作爲絕對路徑返回調用 Path 對象
 Path resolve(Path p) :合併兩個路徑,返回合併後的路徑對應的Path對象
 File toFile(): 將Path轉化爲File類的對象

13-11 NIO.2中Path、 Paths、 Files類的使用Files 類
 java.nio.file.Files 用於操作文件或目錄的工具類。
 Files常用方法:
 Path copy(Path src, Path dest, CopyOption … how) : 文件的複製
 Path createDirectory(Path path, FileAttribute<?> … attr) : 創建一個目錄
 Path createFile(Path path, FileAttribute<?> … arr) : 創建一個文件
 void delete(Path path) : 刪除一個文件/目錄,如果不存在,執行報錯
 void deleteIfExists(Path path) : Path對應的文件/目錄如果存在,執行刪除
 Path move(Path src, Path dest, CopyOption…how) : 將 src 移動到 dest 位置
 long size(Path path) : 返回 path 指定文件的大小

13-11 NIO.2中Path、 Paths、 Files類的使用Files 類
 Files常用方法:用於判斷
 boolean exists(Path path, LinkOption … opts) : 判斷文件是否存在
 boolean isDirectory(Path path, LinkOption … opts) : 判斷是否是目錄
 boolean isRegularFile(Path path, LinkOption … opts) : 判斷是否是文件
 boolean isHidden(Path path) : 判斷是否是隱藏文件
 boolean isReadable(Path path) : 判斷文件是否可讀
 boolean isWritable(Path path) : 判斷文件是否可寫
 boolean notExists(Path path, LinkOption … opts) : 判斷文件是否不存在
 Files常用方法:用於操作內容
 SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 獲取與指定文件的連接, how 指定打開方式。
 DirectoryStream newDirectoryStream(Path path) : 打開 path 指定的目錄
 InputStream newInputStream(Path path, OpenOption…how):獲取 InputStream 對象
 OutputStream newOutputStream(Path path, OpenOption…how) : 獲取 OutputStream 對象

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