Java通道
通道(Channel)是數據源和Java程序之間的開放連接,用於執行I/O操作。Channel接口在java.nio.channels包中。通道(Channel)接口只聲明瞭兩個方法:close()和isOpen()。
各種渠道
ReadableByteChannel用於使用read()方法將數據從數據源讀取到字節緩衝區中。WritableByteChannel用於使用write()方法將數據從字節緩衝區寫入數據宿。
ByteChannel能夠分別使用read()和write()方法讀取和寫入字節數據。ScatteringByteChannel將數據從數據源讀取到多個字節緩衝區中。 從已知的文件格式或類似的數據源讀取數據是有用的,其中在一些固定長度的報頭中提供數據,隨後是可變長度的主體。
GatheringByteChannel從多個字節緩衝區中寫出數據。
創建通道
要獲得一個通道,舊的方式使用java.io包中的類I/O來創建InputStream和OutputStream的對象。java.nio.channels包中的Channels類是一個實用程序類,它有許多靜態方法將流轉換爲通道,反之亦然。
Channels類還提供了將讀寫器轉換爲通道的方法,反之亦然。例如,如果有一個名爲myInputStream的輸入流對象,獲得一個ReadableByteChannel如下:
ReadableByteChannel rbc = Channels.newChannel(myInputStream);
如果有一個名爲rbc的ReadableByteChannel,可以獲得如下的基本InputStream對象:
InputStream myInputStream = Channels.newInputStream(rbc);
FileInputStream和FileOutputStream類有一個稱爲getChannel()的新方法來返回一個FileChannel對象。FileChannel用於讀取和寫入數據到文件。從FileInputStream獲取的FileChannel對象以只讀模式打開。
FileInputStream fis = new FileInputStream("test1.txt");
FileChannel fcReadOnly = fis.getChannel(); // A read-only channel
從FileOutputStream對象獲取的FileChannel對象以只寫模式打開。
FileOutputStream fos = new FileOutputStream("test1.txt");
FileChannel fcWriteOnly = fos.getChannel(); // A write-only channel
如果從RandomAccessFile獲取一個FileChannel,它將以只讀,只寫或讀寫模式打開,這取決於創建RandomAccessFile對象的方式。
以下代碼爲不同種類的文件流獲取FileChannel對象:
// read-only mode
RandomAccessFile raf1 = new RandomAccessFile("test1.txt", "r");
FileChannel rafReadOnly = raf1.getChannel(); // A read-only channel
// read-write mode
RandomAccessFile raf2 = new RandomAccessFile("test1.txt", "rw");
FileChannel rafReadWrite = raf2.getChannel(); // A read-write channel
讀/寫文件
FileChannel對象維護位置變量作爲緩衝區。FileChannel的read()和write()方法有兩種類型:相對位置讀/寫和絕對位置讀/寫。
當打開一個FileChannel時,它的位置設置爲0,這是文件的開始。當使用相對read()方法從FileChannel讀取時,它的位置增加讀取的字節數。
從FileChannel讀取的絕對位置不會影響其位置。可以使用position()方法獲取FileChannel對象的當前位置值。使用position(int newPosition)方法將其位置設置爲新位置。
通道也是可自動關閉的。如果使用try-with-resources語句來獲得一個通道,通道將被自動關閉,這樣就不用顯示地調用通道的close()方法。
以下代碼從名爲test1.txt的文件中讀取文本。
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Main {
public static void main(String[] args) {
File inputFile = new File("test1.txt");
if (!inputFile.exists()) {
System.out.println("The input file " + inputFile.getAbsolutePath()
+ " does not exist.");
System.out.println("Aborted the file reading process.");
return;
}
try (FileChannel fileChannel = new FileInputStream(inputFile).getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (fileChannel.read(buffer) > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
byte b = buffer.get();
System.out.print((char) b);
}
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面的代碼生成以下結果。
The input file F:\website\yiibai\worksp\test1.txt does not exist.
Aborted the file reading process.
示例
以下代碼顯示如何使用緩衝區和通道寫入文件。
import java.io.File;
import java.nio.channels.FileChannel;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) {
File outputFile = new File("test.txt");
try (FileChannel fileChannel = new FileOutputStream(outputFile)
.getChannel()) {
String text = getText();
byte[] byteData = text.toString().getBytes("UTF-8");
ByteBuffer buffer = ByteBuffer.wrap(byteData);
fileChannel.write(buffer);
} catch (IOException e1) {
e1.printStackTrace();
}
}
public static String getText() {
String lineSeparator = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
sb.append("test");
sb.append(lineSeparator);
sb.append("test");
sb.append(lineSeparator);
sb.append("test");
sb.append(lineSeparator);
sb.append("test");
return sb.toString();
}
}
複製文件的內容
可以使用緩衝區和通道來複制文件。獲取源文件和目標文件的FileChannel對象,並對源FileChannel對象調用transferTo()方法或調用目標FileChannel對象上的transferFrom()方法。
以下代碼顯示如何複製文件。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
public class Main {
public static void main(String[] args) throws Exception {
FileChannel sourceChannel = new FileInputStream("sourceFile").getChannel();
FileChannel sinkChannel = new FileOutputStream("newFile").getChannel();
// Copy source file contents to the sink file
sourceChannel.transferTo(0, sourceChannel.size(), sinkChannel);
}
}