通道(Channel
)是數(shù)據(jù)源和Java程序之間的開放連接,用于執(zhí)行I/O
操作。Channel
接口在java.nio.channels
包中。通道(Channel
)接口只聲明了兩個(gè)方法:close()
和isOpen()
。
ReadableByteChannel
用于使用read()
方法將數(shù)據(jù)從數(shù)據(jù)源讀取到字節(jié)緩沖區(qū)中。WritableByteChannel
用于使用write()
方法將數(shù)據(jù)從字節(jié)緩沖區(qū)寫入數(shù)據(jù)宿。
ByteChannel
能夠分別使用read()
和write()
方法讀取和寫入字節(jié)數(shù)據(jù)。ScatteringByteChannel
將數(shù)據(jù)從數(shù)據(jù)源讀取到多個(gè)字節(jié)緩沖區(qū)中。 從已知的文件格式或類似的數(shù)據(jù)源讀取數(shù)據(jù)是有用的,其中在一些固定長(zhǎng)度的報(bào)頭中提供數(shù)據(jù),隨后是可變長(zhǎng)度的主體。
GatheringByteChannel
從多個(gè)字節(jié)緩沖區(qū)中寫出數(shù)據(jù)。
要獲得一個(gè)通道,舊的方式使用java.io
包中的類I/O
來(lái)創(chuàng)建InputStream
和OutputStream
的對(duì)象。java.nio.channels
包中的Channels
類是一個(gè)實(shí)用程序類,它有許多靜態(tài)方法將流轉(zhuǎn)換為通道,反之亦然。
Channels
類還提供了將讀寫器轉(zhuǎn)換為通道的方法,反之亦然。例如,如果有一個(gè)名為myInputStream
的輸入流對(duì)象,獲得一個(gè)ReadableByteChannel
如下:
ReadableByteChannel rbc = Channels.newChannel(myInputStream);
如果有一個(gè)名為rbc
的ReadableByteChannel
,可以獲得如下的基本InputStream
對(duì)象:
InputStream myInputStream = Channels.newInputStream(rbc);
FileInputStream
和FileOutputStream
類有一個(gè)稱為getChannel()
的新方法來(lái)返回一個(gè)FileChannel
對(duì)象。FileChannel
用于讀取和寫入數(shù)據(jù)到文件。從FileInputStream
獲取的FileChannel
對(duì)象以只讀模式打開。
FileInputStream fis = new FileInputStream("test1.txt");
FileChannel fcReadOnly = fis.getChannel(); // A read-only channel
從FileOutputStream
對(duì)象獲取的FileChannel
對(duì)象以只寫模式打開。
FileOutputStream fos = new FileOutputStream("test1.txt");
FileChannel fcWriteOnly = fos.getChannel(); // A write-only channel
如果從RandomAccessFile
獲取一個(gè)FileChannel
,它將以只讀,只寫或讀寫模式打開,這取決于創(chuàng)建RandomAccessFile
對(duì)象的方式。
以下代碼為不同種類的文件流獲取FileChannel
對(duì)象:
// 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
對(duì)象維護(hù)位置變量作為緩沖區(qū)。FileChannel
的read()
和write()
方法有兩種類型:相對(duì)位置讀/寫和絕對(duì)位置讀/寫。
當(dāng)打開一個(gè)FileChannel
時(shí),它的位置設(shè)置為0
,這是文件的開始。當(dāng)使用相對(duì)read()
方法從FileChannel
讀取時(shí),它的位置增加讀取的字節(jié)數(shù)。
從FileChannel
讀取的絕對(duì)位置不會(huì)影響其位置??梢允褂?code>position()方法獲取FileChannel
對(duì)象的當(dāng)前位置值。使用position(int newPosition)
方法將其位置設(shè)置為新位置。
通道也是可自動(dòng)關(guān)閉的。如果使用try-with-resources
語(yǔ)句來(lái)獲得一個(gè)通道,通道將被自動(dòng)關(guān)閉,這樣就不用顯示地調(diào)用通道的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();
}
}
}
上面的代碼生成以下結(jié)果。
The input file F:\website\yiibai\worksp\test1.txt does not exist.
Aborted the file reading process.
以下代碼顯示如何使用緩沖區(qū)和通道寫入文件。
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();
}
}
可以使用緩沖區(qū)和通道來(lái)復(fù)制文件。獲取源文件和目標(biāo)文件的FileChannel
對(duì)象,并對(duì)源FileChannel
對(duì)象調(diào)用transferTo()
方法或調(diào)用目標(biāo)FileChannel
對(duì)象上的transferFrom()
方法。
以下代碼顯示如何復(fù)制文件。
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);
}
}