Java Nio Buffer 七

2018/01/08 Java

Java Nio Buffer 七

打开通道

通道可以分为两大类:File I/O和Stream I/O,分别是文件通道和套接字通道。
通道可以通过多种方式创建,套接字通道有直接创建新通道的工厂方法,文件通道稚嫩狗通过一个打开了的RandomAccessFile,FileInputStreamFileOutputStream对象上调用getChannel()方法来获取。

代码如下:

SocketChannel sc = SocketChannel.open( );
sc.connect (new InetSocketAddress ("somehost", someport));
ServerSocketChannel ssc = ServerSocketChannel.open( );
ssc.socket( ).bind (new InetSocketAddress (somelocalport));
DatagramChannel dc = DatagramChannel.open( );
RandomAccessFile raf = new RandomAccessFile ("somefile", "r");
FileChannel fc = raf.getChannel( );

Java.netsocket类也有新的getChannel()方法。方法可以返回一个相应的socket通道对象,但是不会创建新的通道。

使用通道

通道可以是单向(unidirectional)或者双向的(bidirectional)。一个 channel 类可能实现定义 read()方法的 ReadableByteChannel 接口,而另一个 channel 类也许实现 WritableByteChannel 接口以 提供 write() 方法。实现这两种接口其中之一的类都是单向的,只能在一个方向上传输数据。如果一个类同时实现这两个接口,那么它是双向的,可以双向传输数据。
实现了ByteChannel接口本身的通道是双向的。如图所示: 图一

从类定义的角度而言,全部 file 和 socket 通道对象都是双向的。一个文件可以在不同的时候以不同的权限打开。从 FileInputStream 对象的 getChannel( )方法获取的 FileChannel 对象是只读的,不过从接口声明的角度来看却是双向的,因为 FileChannel 实现 ByteChannel 接口。通道会连接一个特定 I/O 服务且通道实例(channel instance)的性能受它所连接的 I/O 服务的特征限制。一个连接到只读文件的 Channel 实例不能进行写操作,即使该实例所属的类可能有 write( )方法。需要知道通道是如何打开的,避免执行一个底层 I/O 服务不允许的操作。

下文中的代码展示了如何复制两个通道:

public class ChannelCopy
{
   
    public static void main (String [] argv)
        throws IOException
    {
        ReadableByteChannel source = Channels.newChannel (System.in);
        WritableByteChannel dest = Channels.newChannel (System.out);
        channelCopy1 (source, dest);
       
        source.close( );
        dest.close( );
    }

    private static void channelCopy1 (ReadableByteChannel src,
        WritableByteChannel dest)
        throws IOException
        {
            ByteBuffer buffer = ByteBuffer.allocateDirect (16 * 1024);
            while (src.read (buffer) != -1) {

                buffer.flip( );

                dest.write (buffer);

                buffer.compact( );
        }

        buffer.flip( );

        while (buffer.hasRemaining( )) {
            dest.write (buffer);
        }
    }

    private static void channelCopy2 (ReadableByteChannel src,
        WritableByteChannel dest)
        throws IOException
    {
        ByteBuffer buffer = ByteBuffer.allocateDirect (16 * 1024);
        while (src.read (buffer) != -1) {
        
        buffer.flip( );
        
        while (buffer.hasRemaining( )) {
            dest.write (buffer);
        }
        
        buffer.clear( );
        } 
    }
}

通道可以以阻塞(blocking)或非阻塞(nonblocking)模式运行。非阻塞模式的通道永远不会 让调用的线程休眠。请求的操作要么立即完成,要么返回一个结果表明未进行任何操作。只有面向 流的(stream-oriented)的通道,如 sockets 和 pipes 才能使用非阻塞模式。

关闭通道

通道不能被重复使用。一个打开的通道即代表与一个特定 I/O 服务的特定连接并封装该连接的状态。当通道关闭时,那个连接会丢失,然后通道将不再连接任何东西。
调用通道的close( )方法时,可能会导致在通道关闭底层I/O服务的过程中线程暂时阻塞。在一个通道上多次调用close( )方法是没有坏处的,但是如果第一个线程在close( )方法中阻塞,那么在它完成关闭通道之前,任何其他调用close( )方法都会阻塞。

Show Disqus Comments

Search

    Table of Contents