NIO操作实例

NIO

Posted by 王明高 on November 30, 2019

目录操作

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class DirectoryOperationsDemo {

    public static void main(String[] args) {
        String classPath = System.getProperty("java.class.path");
        Stream.of(classPath.split(File.pathSeparator))
                .map(Paths::get) // String -> Path
                .filter(Files::isDirectory) // 过滤目录
                .filter(Files::isReadable)
                .filter(Files::isWritable)
                .map(Path::toString)        // Path -> String
                .map(dirPath -> Paths.get(dirPath, "parent-dir", "sub-dir"))  // Path -> new Path
                .forEach(newDir -> {
                    try {
                        Path newDirectory = Files.createDirectories(newDir);
                        System.out.printf("新的目录[%s] 已被创建!\n", newDirectory);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });

    }
}

文件操作

传统方式操作

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static com.segmentfault.deep.in.java.newfilesystem.PathDemo.USER_DIR_LOCATION;

public class TryWithResourcesDemo {

    public static void main(String[] args) {
        Path pomXmlPath = Paths.get(USER_DIR_LOCATION, "pom.xml");
        Charset charset = Charset.forName("UTF-8");
        try (BufferedReader reader = Files.newBufferedReader(pomXmlPath, charset)) {
            for (String s = reader.readLine(); s != null; s = reader.readLine()) {
                System.out.println(s);
            }
        } catch (IOException e) {
            System.err.format("IOException : %s\n", e.getMessage());
        }
    }

ByteChannel方式操作

import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import static com.segmentfault.deep.in.java.newfilesystem.PathDemo.USER_DIR_LOCATION;

public class FileOperationsUsingByteChannelDemo {

    public static void main(String[] args) {
        Charset charset = Charset.forName("UTF-8");
        Path pomXmlPath = Paths.get(USER_DIR_LOCATION, "pom.xml");
        Path pomCopyXmlPath = Paths.get(USER_DIR_LOCATION, "pom-copy.xml");
        try (SeekableByteChannel sourceByteChannel = Files.newByteChannel(pomXmlPath);
             SeekableByteChannel targetByteChannel = Files.newByteChannel(pomCopyXmlPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
        ) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(16);
            while (sourceByteChannel.read(byteBuffer) > 0) {
                byteBuffer.flip();
                if(byteBuffer.remaining()){
                	targetByteChannel.write(byteBuffer);   
                }
                byteBuffer.clear();
            }
        } catch (IOException e) {

        }
    }
}

文件拷贝

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

public class ChannelRedirect {

    public static void main(String[] args) throws IOException {
        // 传统 InputStream 和 OutputStream
        copy(System.in, System.out);
        // channel方式
        ReadableByteChannel readableByteChannel = Channels.newChannel(System.in);
        WritableByteChannel writableByteChannel = Channels.newChannel(System.out);
        copy(readableByteChannel, writableByteChannel);
    }

    private static void copy(ReadableByteChannel readableByteChannel, WritableByteChannel writableByteChannel) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(4 * 1024); // 4 K字节数组(堆内存)
        while (readableByteChannel.read(buffer) != -1) {
            buffer.flip(); // 记录当前 buffer limit = position (已读数据长度)
            // 优化写入
            if (buffer.hasRemaining()) {
                writableByteChannel.write(buffer);
            }
            buffer.clear();
        }

    }

    private static void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
        byte[] buffer = new byte[4 * 1024]; // 4 K字节数组(堆内存)
        int readLength = -1;
        while ((readLength = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, readLength);
        }
    }
}

套接字操作

传统方式操作

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ChannelClientDemo {
    // select 和 epoll
    public static void main(String[] args) throws IOException, InterruptedException {
        // 客户端 SocketChannel
        try (SocketChannel socketChannel = SocketChannel.open();) {
            // 设置为非阻塞
            socketChannel.configureBlocking(false);
            // 连接服务端
            socketChannel.connect(new InetSocketAddress(8080));
            while (!socketChannel.finishConnect()) {
                System.out.println("等待连接到达...");
            }
            ByteBuffer buffer = ByteBuffer.allocate(8);
            while (socketChannel.read(buffer) != -1) {
                buffer.flip();
                while (buffer.hasRemaining()) {
                    System.out.print((char)buffer.get());
                }
                buffer.clear();
            }
        }
    }
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ChannelServerDemo {
    // select 和 epoll
    public static void main(String[] args) throws IOException, InterruptedException {
        // 服务端 SocketChannel
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();) {
            // 绑定服务端
            serverSocketChannel.socket().bind(new InetSocketAddress(8080));
            // 设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            System.out.println("当前服务器地址:" + serverSocketChannel.socket().getLocalSocketAddress());
            String message = "Hello,World";
            ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());

            while (true) {
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel != null) {
                    // 当连接建立时
                    System.out.printf("接受客户端[%s] 的连接...%n", socketChannel.getRemoteAddress());
                    buffer.rewind();
                    socketChannel.write(buffer); // 写入管道到发送 Socket 请求客户端
                    socketChannel.close();

                } else { // 非阻塞时,执行逻辑
                    Thread.sleep(500);
                }
            }
        }
    }
}

Selector方式操作

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

public class SelectorClientDemo {

    public static void main(String[] args) throws IOException {
        // 客户端 SocketChannel
        try (SocketChannel socketChannel = SocketChannel.open();) {
            // 设置为非阻塞
            socketChannel.configureBlocking(false);
            // 连接服务端
            socketChannel.connect(new InetSocketAddress(8080));
            while (!socketChannel.finishConnect()) {
                System.out.println("等待连接到达...");
            }
            ByteBuffer buffer = ByteBuffer.allocate(8);
            while (socketChannel.read(buffer) != -1) {
                buffer.flip();
                while (buffer.hasRemaining()) {
                    System.out.print(new Date(buffer.getLong()));
                }
                buffer.clear();
            }
        }
    }
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SelectorServerDemo {

    public static void main(String[] args) throws IOException {
        // 服务端 SocketChannel
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();) {
            // 绑定服务端
            serverSocketChannel.socket().bind(new InetSocketAddress(8080));
            // 设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            System.out.println("当前服务器地址:" + serverSocketChannel.socket().getLocalSocketAddress());
            // 打开 Selector
            Selector selector = Selector.open();
            // 注册 OP_ACCEPT
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                int n = selector.select();
                if (n == 0) {
                    continue;
                }
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    if (key.isAcceptable()) {
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        SocketChannel socketChannel = ssc.accept();
                        if (socketChannel == null) {
                            continue;
                        }
                        System.out.printf("接受客户端[%s] 的连接...%n", socketChannel.getRemoteAddress());
                        ByteBuffer buffer = ByteBuffer.allocate(8);
                        // 将服务器当前 timestamp 传递到客户端
                        buffer.putLong(System.currentTimeMillis());
                        buffer.flip();
                        while (buffer.hasRemaining()) {
                            socketChannel.write(buffer);
                        }
                        socketChannel.close();
                        System.out.println("当前服务器时间已发送到客户端");
                    }
                    iterator.remove(); // 移除已接受 SelectionKey
                }
            }
        }
    }
}