主要内容
Java NIO中的常用Channel
前面的文章中介绍的Buffer类用于装载内存中驻留的数据,当这些数据需要持久化的时候,就会使用Channel进行操作,因为Channel通常都会和底层文件绑定,例如FileChannel,和普通IO中的FileStream类似。除了绑定普通的文件外,Channel还可以和网络套接字绑定,例如SocketChannel。
使用FileChannel
FileChannel不能直接实例化,可以使用普通IO类的getChannel()
来获取一个FileChannel的实例。
1 2 3 4 5 6 7 8 9 10 |
//获取一个用于读取数据的FileChannel FileInputStream fileInputStream = new FileInputStream("D:\\test.txt"); FileChannel fileChannel = fileInputStream.getChannel(); //获取一个用于写入数据的FileChannel FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt"); FileChannel outChannel = fileOutputStream.getChannel(); RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\test.txt", "rw"); FileChannel randomChannel = randomAccessFile.getChannel(); |
从通道读取数据到Buffer
实例化Channel后,就可以结合Buffer操作数据,例如从通道读数据进内存(Buffer)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@Test public void usingFileChannel() { try (RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\test.txt", "rw"); FileChannel channel = randomAccessFile.getChannel()) { //获取ByteBuffer的实例 ByteBuffer buffer = ByteBuffer.allocate(1024); // 从channel读取数据到ByteBuffer channel.read(buffer); //转换buffer到读模式 buffer.flip(); while (buffer.hasRemaining()) { // 从buffer读取数据输出到控制台 System.out.print((char) buffer.get()); } } catch (IOException e) { e.printStackTrace(); } } |
把Buffer中的数据传输到Channel
当数据需要持久化的时候,就需要执行这个操作。和普通IO的读写分离不同的是,Channel和Buffer之间的关系是双向的,同一个Channel对象既可以读,也可以写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private void writeDataToChannel() { try (RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\test.txt", "rw"); FileChannel channel = randomAccessFile.getChannel()) { // 使用数据初始化ByteBuffer实例 ByteBuffer buffer = ByteBuffer.wrap("hello java nio".getBytes()); // 数据从buffer写到channel channel.write(buffer); } catch (IOException e) { e.printStackTrace(); } } |
代码中的wrap()
静态方法用于把数据填充到ByteBuffer对象中,填充后buffer的position为0,limit为写入的数据量。需要注意的是:这里不能使用flip()
方法,否则flip()
方法会把position和limit都设置为0,造成没有数据可写。
使用SocketChannel
SocketChannel用于创建基于tcp协议的客户端对象,因为SocketChannel中不存在accept()
方法,所以,它不能成为一个服务端程序。通过connect()
方法,SocketChannel对象可以连接到其他tcp服务器程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@Test public void usingSocketChannel(){ try ( //创建SocketChannel对象 SocketChannel socketChannel = SocketChannel.open();){ //连接到远程服务器 boolean connected = socketChannel.connect(new InetSocketAddress("127.0.0.1", 1000)); ByteBuffer buffer = ByteBuffer.allocate(1024); if (connected){ //read方法会阻塞,直到读取到服务器发送的数据 socketChannel.read(buffer); buffer.flip(); while (buffer.hasRemaining()){ //把接收到的数据输出到控制台 System.out.print((char)buffer.get()); } }else { System.out.println("连接失败"); } } catch (IOException e) { e.printStackTrace(); } } |
使用DatagramChannel
DatagramChannel用于创建基于UDP协议的程序,和SocketChannel不同,UDP协议是无连接的协议,因此,DatagramChannel不需要调用connect()
方法即可接收到数据。但是,UDP协议是可连接的,即我们也可以像SocketChannel一样调用connect()
方法和一个指定的远程主机连接,但是不同的是,DatagramSocket的connect()
方法并不会真的创建一个连接,它的作用只是限制我们只能和这个已连接地址接收和发送数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Test public void usingDatagramChannel(){ try( //创建DatagramChannel对象 DatagramChannel datagramChannel = DatagramChannel.open();){ //绑定本地端口1000 datagramChannel.bind(new InetSocketAddress(1000)); ByteBuffer buffer = ByteBuffer.allocate(1024); //阻塞直到接收到远程数据 datagramChannel.receive(buffer); buffer.flip(); while(buffer.hasRemaining()){ System.out.print((char)buffer.get()); } }catch (IOException e){ e.printStackTrace(); } } |
转载请注明:Pure nonsense » Java NIO 常用通道(Channel)