为什么没有将缓冲区写入FileChannel

时间:2018-09-01 14:43:11

标签: java nio filechannel

我现在正在学习Java NIO,我找到了一个示例来说明FileChannel的收集操作,如下所示:

public class ScattingAndGather {
    public static void main(String args[]) {
        gather();
    }

    public static void gather() {
        ByteBuffer header = ByteBuffer.allocate(10);
        ByteBuffer body = ByteBuffer.allocate(10);

        byte[] b1 = { '0', '1' };
        byte[] b2 = { '2', '3' };
        header.put(b1);
        body.put(b2);

        ByteBuffer[] buffs = { header, body };

        FileOutputStream os = null;
        FileChannel channel = null;
        try {
            os = new FileOutputStream("d:/scattingAndGather.txt");
            channel = os.getChannel();
            channel.write(buffs);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

虽然结果表明文件已经创建,但是它是空的,应该是0123,这个例子有什么问题?

1 个答案:

答案 0 :(得分:2)

出现问题的原因是您从未重置缓冲区的位置。

创建两个ByteBuffer对象时,它们都从零位置开始。每当您向其中添加内容时,它们的位置都会提高,这意味着当您尝试将它们写出时,它们报告为不再需要读取字节。因此,在执行任何此类操作之前,您需要以某种方式重置其位置。

Buffer提供了几种方法,其中最容易使用的是flip()。正如您在文档here中所看到的,其用法如下:

  

翻转此缓冲区。将限制设置为当前位置,然后   该位置设置为零。如果标记已定义,则为   丢弃。

     

在执行一系列通道读取或放置操作之后,调用此方法   为一系列的通道写入或相对获取操作做准备

因此,在将它们写出之前,您需要翻转它们。另外,由于您正在尝试java.nio,所以我不明白为什么不应该使用try with resources语句来管理各种资源。这样,您将避免关闭过多的模板资源,因为这些资源可以手动自动关闭。

使用这些代码可以大大缩小代码的可读性:

public static void gather() {
    ByteBuffer header = ByteBuffer.allocate(10);
    ByteBuffer body = ByteBuffer.allocate(10);

    byte[] b1 = { '0', '1' };
    byte[] b2 = { '2', '3' };
    header.put(b1);
    body.put(b2);

    //flip buffers before writing them out.
    header.flip();
    body.flip();
    ByteBuffer[] buffs = { header, body };

    try(FileOutputStream os = new  FileOutputStream("d:/scattingAndGather.txt");
 FileChannel channel = os.getChannel()) {
    channel.write(buffs);
    } catch (IOException e) {
        e.printStackTrace();
    }
}