今天简单说说Channel。
传统IO中使用stream来进行数据的读取与写入,基础的接口有InputStream、OutputStream、Reader 和 Writer。
可以看到,流都是单向的,写或读只能进行一项。
Channel(通道),是双向的,可读可写。具体的实现有很多,FileChannel、ServerSocketChannel、SocketChannel等等,这里简单看一下FileChannel。
看一眼源码。
FileChannel.java
protected FileChannel() { }
那我们就不能通过new获得FileChannel对象了。
文件操作案例:
把文件内容输出到控制台,并在文件末尾写入:Channel write test.
public void accessFile(){
RandomAccessFile randomAccessFile = null;
FileChannel fileChannel = null;
try {
randomAccessFile = new RandomAccessFile("D:/nio/test.txt", "rw");
fileChannel = randomAccessFile.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(32);
int bytesRead = fileChannel.read(byteBuffer);
while (bytesRead != -1) {
byteBuffer.flip();
while(byteBuffer.hasRemaining()){
System.out.print((char) byteBuffer.get());
}
byteBuffer.clear();
bytesRead = fileChannel.read(byteBuffer);
}
// 定位到文件末尾
fileChannel.position(fileChannel.size());
fileChannel.write(ByteBuffer.wrap("Channel write test.".getBytes()));
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
fileChannel.close();
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
可以看到,RandomAccessFile 对象通过getChannel 方法就可以得到一个FileChannel对象。
中间while中通过read方法把数据读入Buffer,flip后再输出。
后面使用write方法将文本写入文件末尾。可以看到一个Channel既可以read也可以write。
当然用FileInputStream、FileOutputStream等实例也能通过getChannel 方法来获得Channel对象,但是此时的Channel就是单向的。FileInputStream对应的Channel无法写数据,FileOutputStream对应的Channel无法读数据,用起来大概像这样:
文件复制
public void copy(){
FileInputStream fis = null;
FileOutputStream fos = null;
FileChannel fisChannel = null;
FileChannel fosChannel = null;
try {
fis = new FileInputStream("D:/nio/from.txt");
fos = new FileOutputStream("D:/nio/to.txt");
fisChannel = fis.getChannel();
fosChannel = fos.getChannel();
long position = 0;
long count = fisChannel.size();
fisChannel.transferTo(position, count, fosChannel);
//fosChannel.transferFrom(fisChannel, position, count); 等价
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fosChannel.close();
fisChannel.close();
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ServerSocketChannel、SocketChannel 结合后面的 Selector 一起说吧。