nettyNIO程序员

NIO-读写

2016-11-23  本文已影响59人  甚了

NIO 读写

Github Demo

读和写是 I/O 的基本过程。从一个通道中读取很简单:只需创建一个缓冲区,然后让通道将数据读到这个缓冲区中。写入也相当简单:创建一个缓冲区,用数据填充它,然后让通道用这些数据来执行写入操作。

从文件中读取

从一个文件中读取一些数据。

在 NIO 系统中,任何时候执行一个读操作,都是从通道中读取,但不是直接从通道读取。因为所有数据最终都驻留在缓冲区中,所以是从通道读到缓冲区中。
因此读取文件涉及三个步骤:

  1. 从 FileInputStream 获取 Channel;
  2. 创建 Buffer;
  3. 将数据从 Channel 读到 Buffer 中。
三个步骤

会注意到,我们不需要告诉通道要读多少数据到缓冲区中。每一个缓冲区都有复杂的内部统计机制,它会跟踪已经读了多少数据以及还有多少空间可以容纳更多的数据。关于缓冲区统计机制我们稍后再讨论

@Test
public void testRead() {
    try {
        FileInputStream fin = new FileInputStream("/Users/dongsj/workspace/dsj/javaSpace/nettyDemo/src/test/resources/nio/readandshow.log");
        FileChannel fileChannel = fin.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int result = fileChannel.read(buffer);
            
        System.out.println("read : " + result);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

写入文件

在 NIO 中写入文件类似于从文件中读取。

三个步骤

flip()源代码可以看出,该方法将limit指向了缓冲区当前位置 position,并将position设置为0,将mark丢弃

public final Buffer flip() {
       limit = position;
       position = 0;
       mark = -1;
       return this;
   }
  • mark <= position <= limit <= capacity
  • mark : 标示了缓冲区中执行reset操作时,position应该置于的位置
  • position : 标示缓冲区中下一个能够进行读写的位置
  • limit : 标示缓冲区中第一个不能进行读写的位置
  • capacity: 用来指定缓冲区的最大容量,它是不变的

allocate(1024)

public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapByteBuffer(capacity, capacity);
    }

在调用allocate()方法分配缓冲区时,实际上将limit 和 capacity 设置成了同样的大小。更多细节可以参考 Buffer & ByteBuffer源码

注意在这里同样不需要告诉通道要写入多数据。缓冲区的内部统计机制会跟踪它包含多少数据以及还有多少数据要写入。

    @Test
    public void testWrite() {
        byte[] message = "some bytes to write".getBytes();

        try {
            FileOutputStream fout = new FileOutputStream("/Users/dongsj/workspace/dsj/javaSpace/nettyDemo/src/test/resources/nio/writeshow.log");
            FileChannel fileChannel = fout.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            for (int i=0; i < message.length; i++) {
                buffer.put(message[i]);
            }
            buffer.flip();

            fileChannel.write(buffer);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

读&写

将一个文件的所有内容拷贝到另一个文件中。执行三个基本操作:(1)创建一个Buffer,(2)从源文件中将数据读到这个缓冲区中,(3)将缓冲区写入目标文件。这个程序不断重复,直到源文件结束。
程序让我们看到如何检查操作的状态,以及如何使用 clear() 和 flip() 方法重设缓冲区,并准备缓冲区以便将新读取的数据写到另一个通道中。

    @Test
    public void testReadAndWrite() {
        FileInputStream fin;
        FileOutputStream fout;
        FileChannel finChannel, foutChannel;

        try {
            fin = new FileInputStream("/Users/dongsj/workspace/dsj/javaSpace/nettyDemo/src/test/resources/nio/readandshow.log");
            fout = new FileOutputStream("/Users/dongsj/workspace/dsj/javaSpace/nettyDemo/src/test/resources/nio/readandshow.log_copy");
            finChannel = fin.getChannel();
            foutChannel = fout.getChannel();

            ByteBuffer buffer = ByteBuffer.allocate(10);

            int count = -1;
            do {
                count = finChannel.read(buffer);

                buffer.flip();
                foutChannel.write(buffer);
                buffer.clear();
            } while (-1 != count);
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // TODO release
        }
    }

结果
上一篇 下一篇

猜你喜欢

热点阅读