加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 缺少ByteBuffer上的一些绝对方法

发布时间:2020-12-14 05:48:21 所属栏目:Java 来源:网络整理
导读:也许我会以错误的方式解决这个问题,但我在 ByteBuffer 上缺少一些绝对的put方法. 如果你看看ByteBuffer,你会发现大多数put方法都有绝对变量和相对变量. 除了: 将字节数组的部分写入ByteBuffer. 将ByteBuffer写入ByteBuffer. ..而且我需要那些. 要明确ByteBu
也许我会以错误的方式解决这个问题,但我在 ByteBuffer上缺少一些绝对的put方法.

如果你看看ByteBuffer,你会发现大多数put方法都有绝对变量和相对变量.

除了:

>将字节数组的部分写入ByteBuffer.
>将ByteBuffer写入ByteBuffer.

..而且我需要那些.

要明确ByteBuffer有方法:

put(byte[] src,int offset,int length)
 put(ByteBuffer src)

但缺乏:

put(int index,byte[] src,int length)
 put(int index,ByteBuffer src)

我有理由为什么我不想移动缓冲区的位置指针,因此我只想使用绝对put方法.

知道为什么这些方法被遗漏了吗?

我当然可以在不移动缓冲区位置指针的情况下模仿丢失的方法,但这将涉及在源字节上循环. Javadoc明确指出,这些方法(可能)比移动更有效,而不是循环并逐个移动字节.我相信Javadoc,因为我的测试表明相同.我需要从实施中尽可能多地挤出速度,因此我当然倾向于利用我可以获得的任何批量方法……如果它们存在的话.

即使ByteBuffer也缺少部分字节数组移动的绝对get方法.但我目前实际上并不需要这样的方法.但又奇怪的是它不存在.

解决方法

获得所需方法的一种方法是让第二个ByteBuffer共享相同的内存,这样您就可以在不改变原始位置的情况下更改其位置.

不幸的是,slice方法也没有采用位置参数;相反,它使用原始缓冲区的当前位置.所以你做不到:

dstBuffer.slice(100).put(srcBuffer);

这里有一些想法,没有特别的顺序,除了它是我想到的顺序:

>如果它符合您使用缓冲区的方式,您可以使用slice()准备缓冲区的副本,并在需要将数据放在与原始位置无关的位置时保留它.
>如果要绝对放置的位置始终大于或等于原始缓冲区的位置指针,则可以执行以下操作:

dstBuffer.slice().position(desiredPosition - dstBuffer.position()).put(srcBuffer);

不幸的是,由于切片上的位置不允许为负,因此无法放在较早的位置.编辑:没关系,我忘记了duplicate方法.请参阅@ BorisBrodski的好答案.

>如果您没有使用直接字节缓冲区,System.arraycopy简单快捷:

System.arraycopy(
    srcBuffer.array(),srcBuffer.arrayOffset() + srcBuffer.position(),dstBuffer.array(),dstBuffer.arrayOffset() + desiredPosition,srcBuffer.remaining()
);

>如果不需要并发访问,则可以在需要执行绝对放置时暂时更改缓冲区的位置,然后将其放回.如果您需要并发访问但线程争用率较低,则可以同步对缓冲区的所有访问(可能很明显,但为了完整性而包括在内):

synchronize (lock) {
    int originalPosition = dstBuffer.position();
    dstBuffer.position(desiredPosition);
    dstBuffer.put(srcBuffer);
    dstBuffer.position(originalPosition);
}

>如果其他想法都不适合你,你可以破解缓冲区.这很麻烦,但这是一个例子:

private static final sun.misc.Unsafe UNSAFE;
static {
    Object result = null;
    try {
        Class<?> klass = Class.forName("sun.misc.Unsafe");
        for (Field field : klass.getDeclaredFields()) {
            if (field.getType() == klass &&
                (field.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) ==
                    (Modifier.FINAL | Modifier.STATIC)) {
                field.setAccessible(true);
                result = field.get(null);
                break;
            }
        }
    } catch (Throwable t) {}
    UNSAFE = result == null ? null : (sun.misc.Unsafe)result;
}

private static final Field ADDRESS_FIELD;
static {
    Field f;
    try {
        f = Buffer.class.getDeclaredField("address");
        f.setAccessible(true);
    } catch (NoSuchFieldException | SecurityException e) {
        f = null;
    }
    ADDRESS_FIELD = f;
}


public static void absolutePut(ByteBuffer dstBuffer,int dstPosition,ByteBuffer srcBuffer) {
    if (!srcBuffer.isDirect()) {
        absolutePut(dstBuffer,dstPosition,srcBuffer.array(),srcBuffer.remaining());
        return;
    }

    if (UNSAFE != null && ADDRESS_FIELD != null && dstBuffer.isDirect()) {
        try {
            long dstAddress = (long)ADDRESS_FIELD.get(dstBuffer) + dstPosition;
            long srcAddress = (long)ADDRESS_FIELD.get(srcBuffer) + srcBuffer.position();
            UNSAFE.copyMemory(srcAddress,dstAddress,srcBuffer.remaining());
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    } else {
        // fallback to basic loop
        for (int i = srcBuffer.position(); i < srcBuffer.limit(); i++) {
            dstBuffer.put(dstPosition + i,srcBuffer.get(i));
        }
    }
}

public static void absolutePut(ByteBuffer dstBuffer,int srcOffset,int length) {
    if (UNSAFE != null && ADDRESS_FIELD != null && dstBuffer.isDirect()) {
        try {
            long dstAddress = (long)ADDRESS_FIELD.get(dstBuffer) + dstPosition;
            UNSAFE.copyMemory(
                src,UNSAFE.arrayBaSEOffset(byte[].class) + srcOffset,null,length);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    } else {
        // fallback to System.arraycopy
        System.arraycopy(
            src,srcOffset,dstBuffer.arrayOffset() + dstPosition,length);
    }
}

我给这个代码一些最小的测试,混合了直接和非直接缓冲区,看起来没问题.如果反射技术失败(例如,因为您在applet安全沙箱中或Java实现不兼容),它可以回退到更简洁的方法.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读