Java Mapped Byte Buffer - 缓冲区中的垃圾值

Posted

技术标签:

【中文标题】Java Mapped Byte Buffer - 缓冲区中的垃圾值【英文标题】:Java Mapped Byte Buffer - garbage values in buffer 【发布时间】:2018-03-07 03:43:59 【问题描述】:

我正在尝试使用映射字节缓冲区 (Java),我必须在文件上使用 DirectBuffer 来执行一些算术运算:

MappedByteBuffer mbf = new RandomAccessFile("blah.bin", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE,0,100*8L);

问题: - 直接缓冲区是否被归零? 我有一个调试方法,将值转储为

    private void dump()
    for (int i = 0; i < 100; i++) 
        System.out.println(mbf.getDouble(i));
    

有趣的是,当我在写入任何值之前进行转储时,它会转储全零(双打):

当我写信到任何地方时说:

mbf.putDouble(13,100.0);

当我重新运行转储时,它会转储一些随机值:

0.0
0.0
0.0
0.0
0.0
3.16E-322
8.1387E-320
2.0835183E-317
5.333806864E-315
1.36545455721E-312
3.4955636664571E-310
1.8187371284868433E-307
100.0
5.164499756173817E120
0.0
0.0
0.0
0.0
0.0

我的逻辑依赖于零值

if (mbf.getDouble(6)==0.0)
//then do some thing
else
//do some thing else

在编写上述任何条件之前,如何确保将值正确初始化为零?有没有人有类似的问题?解决这种情况的最佳方法是什么?

高度赞赏任何见解。

更多细节: 操作系统:Windows 10 JDK:java版本“1.8.0_111”

提前致谢!

【问题讨论】:

文件在你打开之前是什么? 这是新的应用程序文件。 【参考方案1】:

double 值占用 8 个字节。 (总是在 Java 中,通常在其他一些语言中,但并非总是如此。)来自 javadoc https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#getDouble-int-

读取给定索引处的八个字节,根据当前字节顺序将它们组合成一个双精度值。

当您请求从字节索引 6 开始的双精度时,它实际上使用字节 6 到 13,而字节 13 包含您存储的(非零)值的第一个字节。

【讨论】:

感谢@dave,为准确指出索引,我真的把它们搞砸了,但现在通过乘以 8(double 的大小)来修复。【参考方案2】:

直接缓冲区是否被归零?

我倾向于相信它是零填充的。因为当我使用下面的代码打开 blah.bin 文件时,磁盘上的大小在 Windows 和 linux 上都是 800 字节。

当我重新运行转储时,它会转储一些随机值:

您看到随机值是因为您没有正确移动mapped byte bufferposition。即,整数需要 4 个字节,所以一旦你在索引 0 处读完它,你应该在位置 3 处开始你的下一个整数。同样,对于 double,它是 8 个字节。

package com.test;

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MappedFileGarbage 

    public static void main(String[] args) throws Exception 
        RandomAccessFile raf = new RandomAccessFile("blah.bin", "rw");
        MappedByteBuffer mbf = raf.getChannel().map(FileChannel.MapMode.READ_WRITE,0,100*8L);
        mbf.putInt(1000).putInt(2000).putDouble(4000.0);
        raf.close();

        raf = new RandomAccessFile("blah.bin", "rw");
        mbf = raf.getChannel().map(FileChannel.MapMode.READ_WRITE,0,100*8L);
        dump(mbf);
    


    private static void dump(MappedByteBuffer mbf)
        // Reading the data without manually setting the position, as getXXX(n) methods internally increment the position.
        System.out.println(mbf.getInt(0));
        System.out.println(mbf.getInt(4));
        System.out.println(mbf.getDouble(8));

    // Reading the data via getXXX() method as manually setting the position, as getXXX(n) methods don't increment the position.
    System.out.println(mbf.position());
    System.out.println(mbf.getInt());
    System.out.println(mbf.position(4));
    System.out.println(mbf.getInt());
    System.out.println(mbf.position(8));
    System.out.println(mbf.getDouble());
    System.out.println(mbf.position());

       

希望这会有所帮助。

【讨论】:

谢谢@Madhusudana,你快到了。

以上是关于Java Mapped Byte Buffer - 缓冲区中的垃圾值的主要内容,如果未能解决你的问题,请参考以下文章

Java中一个byte是多少个位元组,如果byte阵列的长度是1024,是1mb的大小吗?

byte数组大小问题

java读取文件时,InputStream的read(byte[])方法的byte[]的长度不知如何设置,请教大虾们

java 缓冲流 Buffer

Java获取文件的byte数组数据

Java NIO中的缓冲区Buffer缓冲区基础