Java NIO 编程

2021-04-12  本文已影响0人  Cook1fan
image.png
image.png
public class BasicBuffer {
    public static void main(String[] args) {
        // 举例说明 Buffer 的使用 (简单说明)
        // 创建一个 Buffer, 大小为 5,即可存放5个int
        IntBuffer intBuffer = IntBuffer.allocate(5);
        // 向 buffer 存放数据
        for (int i = 0; i < intBuffer.capacity(); i++) {
            intBuffer.put(i * 2);
        }
        // 如何从buffer读取数据
        // 将buffer转换,读写切换
        intBuffer.flip();
        while (intBuffer.hasRemaining()) {
            System.out.println(intBuffer.get());
        }
    }
}
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
public class NIOFileChannel01 {
    public static void main(String[] args) throws IOException {
        String str = "hello,尚硅谷";
        // 创建一个输出流-> channel
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\32582\\Desktop\\file01.txt");
        // 通过fileOutputStream获取对应的FileChannel
        // 这个fileChannel真实类型FileChannelImpl
        FileChannel fileChannel = fileOutputStream.getChannel();
        // 创建一个缓冲区 ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        // 将 str 放入到 byteBuffer
        byteBuffer.put(str.getBytes());
        // 对 byteBuffer 进行 flip
        byteBuffer.flip();
        // 将 byteBuffer 数据写入到 fileChannel
        fileChannel.write(byteBuffer);
        fileOutputStream.close();

    }
}
image.png
image.png
public class NIOFileChannel02 {
    public static void main(String[] args) throws IOException {

        // 创建文件输入流
        File file = new File("C:\\Users\\32582\\Desktop\\file01.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        // 通过fileInputStream获取对应的FileChannel
        // 这个fileChannel真实类型FileChannelImpl
        FileChannel fileChannel = fileInputStream.getChannel();
        // 创建一个缓冲区 ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
        // 将 通道的数据读入到 byteBuffer
        fileChannel.read(byteBuffer);
        // 将 byteBuffer 的字节数据转成String
        System.out.println(new String(byteBuffer.array()));
        fileInputStream.close();

    }
}
image.png
image.png
public class NIOFileChannel03 {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = new FileInputStream("1.txt");
        FileChannel fileChannel01 = fileInputStream.getChannel();

        FileOutputStream fileOutputStream = new FileOutputStream("2.txt");
        FileChannel fileChannel02 = fileOutputStream.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(512);

        while (true) {
            // 这里有一个重要的操作,一定不要忘了
            byteBuffer.clear(); // 清空 buffer
            int read = fileChannel01.read(byteBuffer);
            System.out.println("read = " + read);
            if (read == -1) { // 表示读完
                break;
            }
            // 将 buffer中的数据写入到fileChannel02 -- 2.txt
            byteBuffer.flip();
            fileChannel02.write(byteBuffer);
        }

        // 关闭相关的流
        fileInputStream.close();
        fileOutputStream.close();
    }
}
image.png
public class NIOFileChannel04 {
    public static void main(String[] args) throws IOException {

        // 创建相关流
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\32582\\Desktop\\a.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\32582\\Desktop\\a2.jpg");

        // 获取各个流对应的 fileChannel
        FileChannel sourceChannel = fileInputStream.getChannel();
        FileChannel destChannel = fileOutputStream.getChannel();

        // 使用 transferForm 完成拷贝
        destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());

        // 关闭相关通道和流
        sourceChannel.close();
        destChannel.close();
        fileInputStream.close();
        fileOutputStream.close();

    }
}
image.png
public class NIOByteBufferPutGet {
    public static void main(String[] args) {
        // 创建一个Buffer
        ByteBuffer buffer = ByteBuffer.allocate(64);
        // 类型化方式放入数据
        buffer.putInt(100);
        buffer.putLong(9);
        buffer.putChar('尚');
        buffer.putShort((short) 4);
        // 取出
        buffer.flip();
        System.out.println();
        System.out.println(buffer.getShort());
        System.out.println(buffer.getInt());
        System.out.println(buffer.getLong());
        System.out.println(buffer.getLong());
    }
}
public class ReadOnlyBuffer {
    public static void main(String[] args) {
        // 创建一个Buffer
        ByteBuffer buffer = ByteBuffer.allocate(64);
        for (int i = 0; i < 64; i++) {
            buffer.put((byte) i);
        }
        // 读取
        buffer.flip();
        // 得到一个只读的buffer
        ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
        System.out.println(readOnlyBuffer.getClass());
        // 读取
        while (readOnlyBuffer.hasRemaining()) {
            System.out.println(readOnlyBuffer.get());
        }
        readOnlyBuffer.put((byte) 100); // 报异常
    }
}
/**
 * 说明
 * 1 MappedByteBuffer 可以让文件直接在内存(对外内存)修改,操作系统不需要拷贝一次
 */
public class MappedByteBufferTest {
    public static void main(String[] args) throws IOException {

        RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt", "rw");
        // 获取对应的通道
        FileChannel channel = randomAccessFile.getChannel();
        /*
         * 参数1:FileChannel.MapMode.READ_WRITE 使用的读写模式
         * 参数2:0:可以直接修改的起始位置
         * 参数3:5:是映射到内存的大小(不是索引位置),即将1.txt的多少个字节映射到内存
         * 可以直接修改的范围就是0-5
         * 实际类型 DirectByteBuffer
         */
        MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);

        mappedByteBuffer.put(0, (byte) 'H');
        mappedByteBuffer.put(3, (byte) '9');
        // mappedByteBuffer.put(5, (byte) 'Y');

        randomAccessFile.close();
        System.out.println("修改成功");

    }
}
/**
 * Scattering:将数据写入到buffer时,可以采用buffer数组,依次写入【分散】
 * Gathering:从buffer读取数据时,可以采用buffer数组,依次读
 */
public class ScatteringAndGatheringTest {
    public static void main(String[] args) throws IOException {
        // 使用 ServerSocketChannel 和 SocketChannel 网络
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        InetSocketAddress inetSocketAddress = new InetSocketAddress(6666);
        // 绑定端口到socket,并启动
        serverSocketChannel.socket().bind(inetSocketAddress);
        // 创建buffer数组
        ByteBuffer[] byteBuffers = new ByteBuffer[2];
        byteBuffers[0] = ByteBuffer.allocate(5);
        byteBuffers[1] = ByteBuffer.allocate(3);
        // 等客户端连接(telnet)
        SocketChannel socketChannel = serverSocketChannel.accept();
        int messageLength = 8; // 假定从客户端接收8个字节
        // 循环读
        while (true) {
            int byteRead = 0;
            while (byteRead < messageLength) {
                long l = socketChannel.read(byteBuffers);
                byteRead += l;// 累计读取的字节数
                System.out.println("byteRead=" + byteRead);
                // 使用流打印,看看当前的这个buffer的position和limit
                Arrays.stream(byteBuffers)
                        .map(buffer -> "position=" + buffer.position() + ",limit=" + buffer.limit())
                        .forEach(System.out::println);
            }

            // 将所有的buffer进行flip
            Arrays.asList(byteBuffers).forEach(ByteBuffer::flip);
            // 将数据读出显示到客户端
            long byteWrite = 0;
            while (byteWrite < messageLength) {
                long l = socketChannel.write(byteBuffers);
                byteWrite += l;
            }
            // 将所有的buffer,进行clear
            Arrays.asList(byteBuffers).forEach(ByteBuffer::clear);
            System.out.println("byteRead=" + byteRead + " byteWrite=" + byteWrite + " messageLength=" + messageLength);
        }
    }
}
image.png
image.png
image.png
image.png image.png image.png
image.png
public class NIOServer {
    public static void main(String[] args) throws IOException {
        // 创建 ServerSocketChannel -> ServerSocket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 获得一个Selector 对象
        Selector selector = Selector.open();

        // 绑定一个端口 6666, 在服务器端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        // 设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 把 severSocketChannel 注册到 selector 关心事件 OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 循环等待客户端连接
        while (true) {
            // 这里我们等待1秒,如果没有事件发生,返回
            if (selector.select(1000) == 0) { // 没有事件发生
                System.out.println("服务器等待1秒,无连接");
                continue;
            }

            // 如果返回的>0,就获取到相关的 selectionKey 集合
            // 1 如果返回的>0,表示已经获取到关注的事件
            // 2 selector.selectedKeys() 返回关注事件的集合
            // 通过 selectionKeys 反向获取通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            // 遍历 Set<SelectionKey>, 使用迭代器遍历
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while (keyIterator.hasNext()) {
                // 获取到 selectionKey
                SelectionKey key = keyIterator.next();
                // 根据key对应的通道发生的事件做相应处理
                if (key.isAcceptable()) { // 如果是 OP_ACCEPT,有新的客户端连接
                    // 该客户端生成一个 StockChannel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("客户端连接成功,生成了一个 socketChannel " + socketChannel.hashCode());
                    // 将 SocketChannel 设置为非阻塞
                    socketChannel.configureBlocking(false);
                    // 将 socketChannel 注册到 selector, 关注事件为 OP_READ, 同时给 socketChannel
                    // 关联一个 Buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if (key.isReadable()) { // 发生 OP_READ
                    // 通过 key 反向获取到对应 channel
                    SocketChannel channel = (SocketChannel) key.channel();
                    // 获取到该channel关联的buffer
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    channel.read(buffer);
                    System.out.println("from 客户端 " + new String(buffer.array()));
                }

                // 手动从集合中移除当前的 selectionKey, 防止重复操作
                keyIterator.remove();

            }
        }
    }
}
public class NIOClient {
    public static void main(String[] args) throws IOException {
        // 得到一个网络通道
        SocketChannel socketChannel = SocketChannel.open();
        // 设置非阻塞
        socketChannel.configureBlocking(false);
        // 提供服务器端ip和port
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666);
        // 连接服务器
        if (!socketChannel.connect(inetSocketAddress)) {
            while (!socketChannel.finishConnect()) {
                System.out.println("因为连接需要时间,客户端不会阻塞,可以做其他工作");
            }
        }
        // 如果连接成功,就发送数据
        String str = "hello, 尚硅谷";
        // warps a byte array into a buffer
        ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
        // 发送数据,将buffer数据写入channel
        socketChannel.write(buffer);
        System.in.read();
    }
}
image.png
image.png
image.png
image.png
上一篇 下一篇

猜你喜欢

热点阅读