Java NIO

2018-12-20  本文已影响0人  Aiibai
基本概念

-发散汇聚

缓存区

缓冲区就是一个对象,其中有一个数组字段用来存储基本数据元素(除了Boolean),另外有四个属性表示当前读写状态。
Capacity
Limit
Position
Mark

0<=Mark<=Position<=Limit<=Capcatiy
offset

ByteBuffer
get
put
flip
rewind
clear
hasRemaing
remaing

compact
reset
mark

equals
compareTo

批量移动

wrap
allocate

复制,视图
duplicate
slice
asReadOnlyBuffer

字节缓冲区
allocateDirect

字节顺序(endian-ness)

直接缓冲区:JVM 堆外内存
字节缓冲区域其他缓冲区的区别:
字节缓冲区的字节顺序是可以改变的,其他缓冲区不行
只有字节缓冲区可以作为通道的源或目标

为什么要有直接缓冲区
非直接字节缓冲区的内存不一定是连续的,而底层IO操作需要连续内存,所以出现了直接缓冲区,即使给通道的是非直接缓冲区,在使用的时候也是会创建一个临时直接缓冲区。
除了字节缓冲区有直接缓冲区,其他类型的缓冲区都没有直接缓冲区,但是可以作为直接字节缓冲区的视图缓冲区。

缓冲区视图

数据元素视图

通道

通道主要有两类:文件通道和套接字通道
FileChannel
SocketChannel/ ServerSocketChannel / DatagramChannel

通道既可以是单向的也可以是双向的,具体看实现了那几个接口
ReadableByteChannel
WriteableByteChannel

通过FileInputStream 打开的通道是只读的,即使该通道实现了WriteableByteChannel 接口

 RandomAccessFile file = new RandomAccessFile("abc.csv", "r");
        Charset charset = Charset.forName("UTF-8");
        CharsetDecoder decoder = charset.newDecoder();

        FileChannel channel = file.getChannel();
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        CharBuffer charBuffer = CharBuffer.allocate(1024);
        int read = channel.read(buffer);
        while (read != -1) {
            buffer.flip();
            decoder.decode(buffer, charBuffer, false);
            charBuffer.flip();
            System.out.println(charBuffer);
            buffer.compact();
            read = channel.read(buffer);
        }

通道有阻塞和非阻塞模式,只有面向流的 scoketspipes 才能使用非阻塞模式

将非阻塞和选择器组合实现多路复用IO

与缓冲区不同,通道不能被重复使用

通道的 close 方法是阻塞的,具体时间取决于关闭底层IO服务

关闭通道
如果一个现在被通道阻塞,中断该线程,对应的通道也会关闭
此外如果一个线程被中断,再去读通道,通道会关闭

实现了 InterruptibleChannel 接口的通道,在任何时候都可以关闭,即使有线程在该通道上面阻塞。

Scatter/Gather (本地矢量IO)

ScatteringByteChannel GatheringByteChannel

public class Marketing {
    private static final String DEMOGRAPHIC = "abc.txt";
    // These are just representative; add your own
    private static String[] col1 = {
            "Aggregate", "Enable", "Leverage",
            "Facilitate", "Synergize", "Repurpose",
            "Strategize", "Reinvent", "Harness"
    };
    private static String[] col2 = {
            "cross-platform", "best-of-breed", "frictionless",
            "ubiquitous", "extensible", "compelling",
            "mission-critical", "collaborative", "integrated"
    };
    private static String[] col3 = {
            "methodologies", "infomediaries", "platforms",
            "schemas", "mindshare", "paradigms",
            "functionalities", "web services", "infrastructures"
    };
    private static String newline = System.getProperty("line.separator");
    private static Random rand = new Random();

    public static void main(String[] args) throws IOException {

        int reps = 10;

        if (args.length > 0) {
            reps = Integer.parseInt(args[0]);
        }

        FileOutputStream outputStream = new FileOutputStream(DEMOGRAPHIC);
        FileChannel channel = outputStream.getChannel();

        ByteBuffer[] buffers = utterBS(reps);
        while (channel.write(buffers) > 0) {

        }
        outputStream.close();
        channel.close();

        FileInputStream inputStream = new FileInputStream(DEMOGRAPHIC);
        FileChannel channel1 = inputStream.getChannel();

        Arrays.stream(buffers).forEach(Buffer::clear);
        while (channel1.read(buffers) > 0) {

        }

        Charset charset = Charset.forName("UTF-8");
        CharsetDecoder decoder = charset.newDecoder();
        CharBuffer charBuffer;
        for (ByteBuffer readBuffer : buffers) {
            charBuffer = CharBuffer.allocate(readBuffer.limit());
            readBuffer.flip();
            decoder.decode(readBuffer, charBuffer, false);
            charBuffer.flip();
            System.out.println(charBuffer);
        }

        System.out.println("All Buffer Data has write to file");
    }

    public static ByteBuffer[] utterBS(int howMany) {
        List<ByteBuffer> buffers = new LinkedList<>();
        for (int i = 0; i < howMany; i++) {
            buffers.add(pickRandom(col1, " "));
            buffers.add(pickRandom(col2, " "));
            buffers.add(pickRandom(col3, newline));
        }

        ByteBuffer[] byteBuffers = new ByteBuffer[buffers.size()];
        buffers.toArray(byteBuffers);
        return byteBuffers;
    }

    public static ByteBuffer pickRandom(String[] strings, String suffix) {
        String string = strings[rand.nextInt(strings.length)];
        byte[] bytes = string.getBytes();
        byte[] bytes1 = suffix.getBytes();
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bytes.length + bytes1.length);
        byteBuffer.put(bytes);
        byteBuffer.put(bytes1);
        byteBuffer.flip();
        return byteBuffer;
    }
}

FileChannel 类保证同一Java 虚拟机上的所有实例看到的某个文件的视图是一直的。
FileChannel 是线程安全的

position 表示接下来文件读或写的位置,由channel 和 文件描述符共享

上一篇 下一篇

猜你喜欢

热点阅读