IO用法几例

http://tutorials.jenkov.com/java-nio/buffers.html

IO

一个例子

public class DemoServer extends Thread {
    private ServerSocket serverSocket;

    public int getPort() {
        return serverSocket.getLocalPort();
    }

    @Override
    public void run() {
        try {
            serverSocket = new ServerSocket(0);    // 绑定0端口
            while (true) {
                Socket socket = serverSocket.accept();      // 调用accept方法,阻塞等待客户端连接
                RequestHandler requestHandler = new RequestHandler(socket);
                requestHandler.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        DemoServer server = new DemoServer();
        server.start();        
        try (Socket client = new Socket(InetAddress.getLocalHost(), server.getPort())) {    // 模拟socket客户端
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            bufferedReader.lines().forEach(s -> System.out.println(s));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class RequestHandler extends Thread {
    private Socket socket;
    RequestHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try (PrintWriter out = new PrintWriter(socket.getOutputStream());) {
            out.println("hello");
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

线程启动

每个都开一个线程过于浪费,线程池改进

            serverSocket = new ServerSocket(0);
            executorService = Executors.newFixedThreadPool(8);
            while (true) {
                Socket socket = serverSocket.accept();
                RequestHandler requestHandler = new RequestHandler(socket);
//                requestHandler.start();
                executorService.execute(requestHandler);
            }

并发量不大的情况这种同步阻塞方式是可以的,但是由于线程的上下文切换是废性能的,在高并发情况下显然不合适。

NIO例子

public class NIOServer extends Thread {

    @Override
    public void run() {
        try (Selector selector = Selector.open();
             ServerSocketChannel serverSocket = ServerSocketChannel.open();) {
            serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
            serverSocket.configureBlocking(false);
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iter = selectionKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    sayHello((ServerSocketChannel) key.channel());
                    iter.remove();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sayHello(ServerSocketChannel server) {
        try (SocketChannel client  = server.accept()) {
            client.write(Charset.defaultCharset().encode("hello"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

NIO利用了单线程轮询事件的机制,通过高效地定位就绪的Channel,来决定做什 么,仅仅select阶段是阻塞的,可以有效避免大量客户端连接时,频繁线程切换带来的问题,应用的扩展能力有了非常大的提高。下面这张图对这种实现思路进行了形象地说明。

NIO2,异步IO

通过指定CompletionHandler回调接口,在accept/read/write等关键节点,通过事件机制调用。

文件拷贝

        try (InputStream inputStream = new FileInputStream(source);
             OutputStream outputStream = new FileOutputStream(dest)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try (FileChannel sourceChanel = new FileInputStream(source).getChannel();
            FileChannel targetChanel = new FileOutputStream(dest).getChannel()) {
            for (long count = sourceChanel.size(); count > 0; ) {
                long transferred = sourceChanel.transferTo(sourceChanel.position(),
                        count, targetChanel);
                sourceChanel.position(sourceChanel.position() + transferred);
                count -= transferred;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

end

参照第一个链接可练习。

一个没有高级趣味的人。 email:hushui502@gmail.com
原文地址:https://www.cnblogs.com/CherryTab/p/12170855.html