5、Channel

    5、Channel

        通道(Channel)用于源节点与目标节点的连接,在Java NIO中负责缓冲区中数据的传输,Channel本身不存储数据,因为需要配合缓冲区进行传输。Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。

        (1)、Channel接口实现类

            ①、FileChannel

                从文件中读写数据。

            ②、SocketChannel

                能通过TCP读写网络中的数据。

            ③、ServerSocketChannel

                可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

            ④、DatagramChannel

                能通过UDP读写网络中的数据。

        (2)、获取Channel方式

            ①、getChannel()方法

                Java针对支持通道的类提供了getChannel()方法。

                本地IO:FileInputStream/FileOutputStream、RandomAccessFile

                网络IO:Socket、ServerSocket、DatagramSocket

            ②、在JDK1.7中的NIO.2针对各个通道提供了静态方法open()

            ③、在JDK1.7中的NIO.2的Files工具类的newByteChannel()

        (3)、AbstractSelectableChannel类

            SelectableChannel抽象类,其子类:SocketChannel类、ServerSocketChannel类

public abstract class AbstractSelectableChannel extends SelectableChannel {
    /**
     * 注册一个选择器并设置监听事件,最后一个参数可以设置共享数据
     */
    public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { ... }
    /**
     * 设置阻塞或非阻塞模式,取值false表示采用非阻塞模式
     */
    public final SelectableChannel configureBlocking(boolean block) throws IOException { ... }
}

        (4)、SocketChannel类

            网络IO通道,具体负责进行读写操作。NIO把缓冲区的数据写入通道,或者把通道里的数据读到缓冲区。

            ①、核心方法

public abstract class SocketChannel extends AbstractSelectableChannel
   implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel {
    /**
     * 获取一个SocketChannel通道
     */
    public static SocketChannel open() throws IOException { return SelectorProvider.provider().openSocketChannel(); }
    /**
     * 连接服务器
     */
    public abstract boolean connect(SocketAddress remote) throws IOException;
    /**
     * 如果上面的方法连接失败,接下来就要通过该方法完成连接操作
     */
    public abstract boolean finishConnect() throws IOException;
    /**
     * 从通道里读数据
     */
    public abstract int read(ByteBuffer dst) throws IOException;
    /**
     * 往通道里写数据
     */
    public abstract int write(ByteBuffer src) throws IOException;
}

        (5)、ServerSocketChannel类

            在服务器端监听新的Socket连接

            ①、核心方法

public abstract class ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel
{
    /**
     * 得到一个ServerSocketChannel对象,new ServerSocketChannelImpl()
     */
    public static ServerSocketChannel open() throws IOException {
        return SelectorProvider.provider().openServerSocketChannel();
    }
    /**
     * 设置服务器端端口号
     */
    public final ServerSocketChannel bind(SocketAddress local) throws IOException
    {
        return bind(local, 0);
    }
    /**
     * 接收一个连接,返回代表这个连接的通道对象
     */
    public abstract SocketChannel accept() throws IOException;
}

        (6)、FileChannel类

            ①、transferTo()方法

                把数据从当前通道复制到目标通道。

/**
 * 将字节从此通道的文件传输到给定的可写入字节通道。
 * 尝试从该通道文件中的给定position开始读取最多count个字节,并将它们写入目标通道。 调用此方法可能会也可能不会传输所有请求的字节; 是否这样做取决于渠道的性质和状态。 如果此通道的文件包含从给定的position开始的少于count字节,或者目标通道是非阻塞且其输出缓冲区中的count字节少于position ,则传输的字节数少于所请求的字节数。
 * @param position - 文件中的位置,从此位置开始传输;必须为非负数
 * @param count - 要传输的最大字节数;必须为非负数
 * @param target - 目标通道
 * @return - 实际已传输的字节数,可能为零
 */
public abstract long transferTo(long position, long count, WritableByteChannel target);

            ②、transferFrom()方法

                从目标通道中复制数据到当前通道。

/**
 * 从给定的可读字节通道将字节传输到此通道的文件中。
 * 尝试从源通道读取最多count个字节,并从给定的position开始将它们写入此通道的文件。 调用此方法可能会也可能不会传输所有请求的字节; 是否这样做取决于渠道的性质和状态。 如果源通道剩余少于count个字节,或者源通道非阻塞且输入缓冲区中立即可用的字节数少于count少于count字节数。
 * @param src - 源通道
 * @param position - 文件在转移开始时的位置; 必须是非负面的
 * @param count - 要传输的最大字节数; 必须是非负面的
 * @return
 */
public abstract long transferFrom(ReadableByteChannel src, long position, long count);

            ③、read(ByteBuffer dst)方法

                从通道读取数据并放到缓冲区中

public abstract int read(ByteBuffer dst) throws IOException;

            ④、write(ByteBuffer src)方法

                把缓冲区的数据写到通道中

public abstract int write(ByteBuffer src) throws IOException;

            ⑤、FileOutputStream、FileInputStream类,内部包含channel变量

public class FileInputStream extends InputStream {
    private FileChannel channel = null;
}

public class FileOutputStream extends InputStream {
    private FileChannel channel = null;
}

            ⑥、代码实现

/**
 * 实现将1.jpg复制,命名为2.jpg
 * 使用直接缓冲区完成文件的复制(内存映射文件)
 */
public void test1() throws IOException {
    FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    // 内存映射文件
    MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
    MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
    // 直接对缓冲区进行数据的读写操作
    byte[] dst = new byte[inMappedBuf.limit()];
    inMappedBuf.get(dst);
    outMappedBuf.put(dst);
    //关闭通道
    inChannel.close();
    outChannel.close();
}
/**
 * 实现将1.jpg复制,命名为2.jpg
 * 利用通道直接的数据传输(直接缓冲区)
 */
public void test2() throws IOException {
    FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    //通道间数据传输
    inChannel.transferTo(0, inChannel.size(), outChannel);
    outChannel.transferFrom(inChannel, 0, inChannel.size());
    //关闭通道
    inChannel.close();
    outChannel.close();
}

你可能感兴趣的:(Java,java,Channel,nio,buffer)