java - 获取相对于原始 ByteBuffer 的直接 ByteBuffer 切片位置

标签 java nio

如果已知它是其他缓冲区?

我知道这可以通过非直接数组支持的 ByteBuffer 使用 arrayOffset() 方法来完成,如下所示:

int getRelativeBufferOffset(ByteBuffer parentBuffer, ByteBuffer childBuffer)
{
  return childBuffer.arrayOffset() - parentBuffer.arrayOffset();
}

void example()
{
  ByteBuffer buffer1 = ByteBuffer.allocate(10000);
  buffer1 .position(22);
  ByteBuffer buffer2 = buffer1.slice();
  buffer2.position(55);
  ByteBuffer buffer3 = buffer2.slice();

  // returns 22
  getRelativeBufferOffset(buffer1, buffer2);

  // returns 55
  getRelativeBufferOffset(buffer2, buffer3);

  // returns 77
  getRelativeBufferOffset(buffer1, buffer3);
}

我认为没有任何东西可以免费用于直接缓冲区。为了获得类似的东西,我能想到的最佳选择是扩展 ByteBuffer 以存储对创建它的缓冲区(父缓冲区)的引用以及相对于父缓冲区的零位置它的创建位置。

编辑:令人恼火的是,我似乎无法扩展 ByteBuffer,因为它的构造函数都不可见。我想我将不得不编写某种包装类。

最佳答案

这是可能的,使用反射。但根据您想要实现的目标,您应该考虑替代解决方案。目前尚不清楚您需要此偏移量的目的。 “务实”的建议是将缓冲区包装到一个简单的、自己的类中,比如

class SlicedBuffer {
    int getBuffer() { ... }
    Buffer getParent() { ... }
    int getOffsetToParent() { ... }
}

并使用这个,但不清楚这是否适用于您的情况。

我将在此处发布使用反射的代码,但请注意

// Many things...
// ... can go ...
// ... wrong when...
// ... using reflection

所以这只是一个演示:

import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;

public class DirectByteBufferSliceOffsetsTest
{
    public static void main(String[] args)
    {
        testArray();
        testDirect();
    }

    private static void testArray()
    {
        System.out.println("Array: ");

        ByteBuffer buffer1 = ByteBuffer.allocate(10000);
        buffer1.position(22);
        ByteBuffer buffer2 = buffer1.slice();
        buffer2.position(55);
        ByteBuffer buffer3 = buffer2.slice();

        // prints 22
        System.out.println(getRelativeBufferOffsetArray(buffer1, buffer2));

        // prints 55
        System.out.println(getRelativeBufferOffsetArray(buffer2, buffer3));

        // prints 77
        System.out.println(getRelativeBufferOffsetArray(buffer1, buffer3));
    }

    private static int getRelativeBufferOffsetArray(
        ByteBuffer parentBuffer, ByteBuffer childBuffer)
    {
        return childBuffer.arrayOffset() - parentBuffer.arrayOffset();
    }


    private static void testDirect()
    {
        System.out.println("Direct: ");

        ByteBuffer buffer1 = ByteBuffer.allocateDirect(10000);
        buffer1.position(22);
        ByteBuffer buffer2 = buffer1.slice();
        buffer2.position(55);
        ByteBuffer buffer3 = buffer2.slice();

        // prints 22
        System.out.println(getRelativeBufferOffsetDirect(buffer1, buffer2));

        // prints 55
        System.out.println(getRelativeBufferOffsetDirect(buffer2, buffer3));

        // prints 77
        System.out.println(getRelativeBufferOffsetDirect(buffer1, buffer3));
    }

    private static int getRelativeBufferOffsetDirect(
        ByteBuffer parentBuffer, ByteBuffer childBuffer)
    {
        long parentAddress = getAddress(parentBuffer);
        long childAddress = getAddress(childBuffer);
        int offset = (int)(childAddress - parentAddress);
        return offset;
    }

    private static long getAddress(Buffer buffer)
    {
        Field f = null;
        try
        {
            f = Buffer.class.getDeclaredField("address");
            f.setAccessible(true);
            return f.getLong(buffer);
        }
        catch (NoSuchFieldException e)
        {
            // Many things...
            e.printStackTrace();
        }
        catch (SecurityException e)
        {
            // ... can go ...
            e.printStackTrace();
        }
        catch (IllegalArgumentException e)
        {
            // ... wrong when...
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            // ... using reflection
            e.printStackTrace();
        }
        finally
        {
            if (f != null)
            {
                f.setAccessible(false);
            }
        }
        return 0;
    }
}

关于java - 获取相对于原始 ByteBuffer 的直接 ByteBuffer 切片位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25566539/

相关文章:

java - 从android中的linikedList中删除项目

java - FileChannel.force 和 FileDescriptor.sync 都需要吗?

JAVA - 不可写 channel 异常

Java Files.copy 在访问被拒绝时删除文件

java - 运行时调整 JScrollPane(包含 JTable)的大小

java - Imagej 16 位有符号缓冲图像

java - FileChannel.read(ByteBuffer) 是否像 RandomAccessFile.readFully(byte[]) 一样工作?

java - 文件遍历不返回绝对路径,仅返回文件名

java - 寻找为酒店管理系统的预订和约会编写日历(用于 gui)的方法

java - 您能帮我理解这个供应商和这个 Java 构造中的分配吗?