Java NIO系列教程(二) Channel
原文链接 作者:Jakob Jenkov 译者:airu 校对:丁一
Java NIO的通道类似流,但又有些不同:
- 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
- 通道可以异步地读写。
- 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道。如下图所示:
Channel的实现
这些是Java NIO中最重要的通道的实现:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
FileChannel 从文件中读写数据。
DatagramChannel 能通过UDP读写网络中的数据。
SocketChannel 能通过TCP读写网络中的数据。
ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
基本的 Channel 示例
下面是一个使用FileChannel读取数据到Buffer中的示例:
[code lang=”java”]
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
System.out.println("Read " + bytesRead);
buf.flip();
while(buf.hasRemaining()){
System.out.print((char) buf.get());
}
buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();
[/code]
注意 buf.flip() 的调用,首先读取数据到Buffer,然后反转Buffer,接着再从Buffer中读取数据。下一节会深入讲解Buffer的更多细节。
原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Java NIO系列教程(二) Channel
基本的 Channel 示例中,为什么还要执行这一句:bytesRead = inChannel.read(buf);(第17行)
这句表示处理完后继续从channel中读取数据。并无他意。
这你都看不懂,前面循环体里把所有的数据都读取完了,bytesRead = inChannel.read(buf);是为了返回-1无数据可读退出循环体
alert(“test”);
好坏的童鞋。。。
inChannel为何不关闭?
因为RandomAccessFile的close方法会将对应的非空channel关闭。(参看jdk源码)
这个例子能行么 如果文件大于48呢
buf.clear(); 会清空buf中的数据,然后bytesRead = inChannel.read(buf);会把通道中的数据再次读入到buf中,所以文件大于48木有问题。
为何要用随机流获取channel
也可以使用其他流的,因为FileChannel只能通过流的Channel获得
alert(‘test’);
ss
alert(‘test’);
alert(‘haha’);
alert(“test”);
谢谢好文!
“注意 buf.flip() 的调用,首先读取数据到Buffer,然后反转Buffer,接着再从Buffer中读取数据”直译成“反转”好像很容易歧义吧,从代码上下文看该方法的功能应该是把指针移到开始位置。
看源码,也是这个意思。
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
不好意思自己理解错了,仔细看下源码周边,应该是”切换“和”反转“的意思,表示表示Buffer从写状态切换到读状态。即把limit设置成当前位置,即写操作写到位置;position设置为0,表示从头读,mark标记清除掉。
LZ请指正啊。。
不太能理解楼主为何会把flip翻译为反转,这里应该是重置的意思吧。
flip()的具体操作就是把Buffer的limit固定到当前的position,然后把position归零。
是的,不过在这里只是重置了position,以供buf.hasRemaining()使用
alert(‘test’);
代码建议格式化一下,不然很难看
写了一个可以读中文的代码
@Test
public void channelTest() throws IOException {
// System.out.println(System.getProperty(“user.dir”));
RandomAccessFile aFile = new RandomAccessFile(“data/nio-data.txt”,”rw”);
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int byteRead = inChannel.read(buf);
while(byteRead != -1){
System.out.println(“Read “+byteRead);
buf.flip();
byte[] bytes = new byte[byteRead];
int index = 0;
while(buf.hasRemaining()){
bytes[index] = buf.get();
index ++;
}
System.out.println(new String(bytes,”utf-8”));
buf.clear();
byteRead = inChannel.read(buf);
}
aFile.close();
}
alert(“2开花”);
package demo.nio;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/*
* 该程序步骤:
* 1. 读取文件获取FileChannel;
* 2. 将ByteBuffer分配大小,并得到ByteBuffer
* 3. 将通道的数据读取到buffer(读取的数据是将数据一次性读到buffer,如果buffer太小,那么读到的文件数据就会缺失);返回值为读取数,读完为-1;
* 4. 将buffer中的limit定位到文件尾,也就是如果文件大小229,你设置buffer的limit为1000,他会将limit设为229;
* 5. 如果读取位置和limit之间还有数据,打印byte数据
* 6. 关闭buffer;
* 7. 关闭channel;
*/
public class FileChannelDemo {
public static void main(String[] args) throws IOException {
RandomAccessFile aFile = new RandomAccessFile(“C:\\Users\\28256\\Desktop\\test.txt”, “rw”);
FileChannel inChannel = aFile.getChannel();
//分配缓存区大小
ByteBuffer buf = ByteBuffer.allocate(1000);
int bytesRead = 0;
while((bytesRead = inChannel.read(buf)) != -1) {
System.out.println(“Read” + bytesRead);
buf.flip();
while(buf.hasRemaining()) {
System.out.println((char)buf.get());
}
buf.clear();
inChannel.read(buf);
}
aFile.close();
}
}