標籤:目標 編碼 image mac 關閉 表示 length 速度 class
package com.java.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.RandomAccessFile;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class GetChannel { private static final int BSIZE = 1024; @SuppressWarnings("resource") public static void main(String[] args) throws Exception { // 擷取通道,該通道允許寫操作 FileChannel fc = new FileOutputStream("data.txt").getChannel(); // 將位元組數組封裝到緩衝區中 fc.write(ByteBuffer.wrap("Some text ".getBytes())); // 關閉通道 fc.close(); // 隨機讀寫檔案流建立的管道 fc = new RandomAccessFile("data.txt", "rw").getChannel(); // fc.position()計算從檔案的開始到當前位置之間的位元組數 // 設定此通道的檔案位置,fc.size()此通道的檔案的當前大小,該條語句執行後,通道位置處於檔案的末尾 fc.position(fc.size()); // Move to the end fc.write(ByteBuffer.wrap("Some more".getBytes())); fc.close(); // Read the file: fc = new FileInputStream("data.txt").getChannel(); ByteBuffer buff = ByteBuffer.allocate(BSIZE); // 將檔案內容讀到指定的緩衝區中 fc.read(buff); //buffer.flip();一定得有,如果沒有,就是從檔案最後開始讀取的,當然讀出來的都是byte=0時候的字元。 //通過buffer.flip();這個語句,就能把buffer的當前位置更改為buffer緩衝區的第一個位置。 buff.flip(); while(buff.hasRemaining()){ System.out.print((char)buff.get()); } }}View Code對於唯讀訪問,我們必須顯式地使用靜態allocate()方法來分配ByteBuffer。 nio的目標就是快速移動大量資料,因此ByteBuffer的大小就顯得尤為重要一一實際上,這裡使用的lK可能比我們通常要使用的小一點(必須通過實際運行應用程式來找到最佳尺寸). 一旦調用read()來告知FileChannel向ByteBuffer儲存位元組,就必須調用緩衝器上的flip(). 讓它做好讓別人讀取位元組的準備(是的,這似乎有一點拙劣,但是請記住,它是很拙劣的,但卻適用於在取最大速度) 如果我們打算使用緩衝器執行進一步的read()操作,我們也必須得調用clear()來為每個read()做好準備.這在下面這個簡單檔案複製程式中可以看到:
package com.java.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class ChannelCopy { private static final int BSIZE = 1024; public static void main(String[] args) throws Exception { if(args.length != 2) { System.out.println("arguments: sourcefile destfile"); System.exit(1); } FileChannel in = new FileInputStream(args[0]).getChannel(), out = new FileOutputStream(args[1]).getChannel(); ByteBuffer buffer = ByteBuffer.allocate(BSIZE); while(in.read(buffer) != -1) { buffer.flip(); // Prepare for writing out.write(buffer); buffer.clear(); // Prepare for reading } }}View Code可以看到,開啟~個FileChannel以用於讀,而開啟另一個以用於寫。ByteBuffer被分配了空間,當FileChannel.read()返回- 1時(一個分界符,毋庸置疑,色源於Unix和C) .表示我們已經到達了輸入的末尾。每次read()操作之後,就會將資料輸入到緩衝器中. flip()則是準備緩衝器以便它的資訊可以由write()提取. write()操作之後,資訊仍在緩衝器中,接著clear()操作則對所有的內部指標重新安排,以便緩衝器在另一個read()操作期間能夠做好接受資料的準備。 然而,上面那個程式並不是處理此類操作的理想方式.特殊方法transferTo()和transferFrom()則允許我們將一個通道和另一個通道直接相連:
package com.java.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.channels.FileChannel;public class TransferTo { public static void main(String[] args) throws Exception { if(args.length != 2) { System.out.println("arguments: sourcefile destfile"); System.exit(1); } FileChannel in = new FileInputStream(args[0]).getChannel(), out = new FileOutputStream(args[1]).getChannel(); in.transferTo(0, in.size(), out); // Or: // out.transferFrom(in, 0, in.size()); }}View Code
1 轉換資料 回過頭看GetChannel.java這個程式就會發現,為了輸出檔案中的資訊,我們必須每次唯讀取一個位元組的資料,然後將每個byte類型強制轉換成char類型。這種方法似乎有點原始-一如果我們查看一下java.nio.CharBuffer這個類,將會發現它有一個toString()方法是這樣定義的: "返回一個包含緩衝器中所有字元的字串。"既然ByteBuffer可以看作是具有asCharBuffer()方法的CharBuffer ,那麼為什麼不用它呢?正如下面的輸出語句中第一行所見,這種方法並不能解決問題:
package com.java.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.nio.charset.Charset;public class BufferToText { private static final int BSIZE = 1024; @SuppressWarnings("resource") public static void main(String[] args) throws Exception { FileChannel fc = new FileOutputStream("data2.txt").getChannel(); fc.write(ByteBuffer.wrap("Some text".getBytes())); fc.close(); fc = new FileInputStream("data2.txt").getChannel(); ByteBuffer buff = ByteBuffer.allocate(BSIZE); fc.read(buff); buff.flip(); // Doesn‘t work: System.out.println(buff.asCharBuffer()); // Decode using this system‘s default Charset: buff.rewind(); String encoding = System.getProperty("file.encoding"); System.out.println("Decoded using " + encoding + ": " + Charset.forName(encoding).decode(buff)); // Or, we could encode with something that will print: fc = new FileOutputStream("data2.txt").getChannel(); fc.write(ByteBuffer.wrap("Some text".getBytes("UTF-16BE"))); fc.close(); // Now try reading again: fc = new FileInputStream("data2.txt").getChannel(); buff.clear(); fc.read(buff); buff.flip(); System.out.println(buff.asCharBuffer()); // Use a CharBuffer to write through: fc = new FileOutputStream("data2.txt").getChannel(); buff = ByteBuffer.allocate(24); // More than needed buff.asCharBuffer().put("Some text"); fc.write(buff); fc.close(); // Read and display: fc = new FileInputStream("data2.txt").getChannel(); buff.clear(); fc.read(buff); buff.flip(); System.out.println(buff.asCharBuffer()); }}View Code緩衝器容納的是普通的位元組,為了把它們轉換成字元,我們要麼在輸入它們的時候對其進行編碼(這樣,它們輸出時才具有意義) .要麼在將其從緩衝器輸出時對它們進行解碼。可以使用java.nio.charset.Charset類實現這些功能,該類提供了把資料編碼成多種不同類型的字元集的工具
---------------
ThinkJava-新IO