【问题标题】:Remove first n bytes from a ByteBuffer从 ByteBuffer 中删除前 n 个字节
【发布时间】:2013-08-03 10:36:59
【问题描述】:

如何在不改变或降低容量的情况下从 ByteBuffer 中删除前 n 个字节?结果应该是第 0 个字节是 n+1 字节。 Java 中是否有更好的数据类型来执行此类操作?

【问题讨论】:

  • 您要将第一个n 字节中的每一个设置为零,还是跳过第一个n 字节?

标签: java bytebuffer


【解决方案1】:

你可以试试这样的:

public void removeBytesFromStart(ByteBuffer bf, int n) {
    int index = 0;
    for(int i = n; i < bf.position(); i++) {
        bf.put(index++, bf.get(i));
        bf.put(i, (byte)0);
    }
    bf.position(index);
}

或者是这样的:

public void removeBytesFromStart2(ByteBuffer bf, int n) {
    int index = 0;
    for(int i = n; i < bf.limit(); i++) {
        bf.put(index++, bf.get(i));
        bf.put(i, (byte)0);
    }
    bf.position(bf.position()-n);
}

这使用ByteBuffer 类的绝对getput 方法,并将position 设置在下一个写入位置。

请注意,绝对 put 方法是可选的,这意味着扩展抽象类 ByteBuffer 的类可能不会为其提供实现,例如它可能会抛出 ReadOnlyBufferException

您是选择循环到position 还是循环到limit 取决于您如何使用缓冲区,例如,如果您手动设置position,您可能希望使用循环到limit。如果你不这样做,那么循环到position 就足够了,而且效率更高。

这里有一些测试:

@Test
public void removeBytesFromStart() {
    ByteBuffer bf = ByteBuffer.allocate(16);
    int expectedCapacity = bf.capacity();
    bf.put("abcdefg".getBytes());

    ByteBuffer expected = ByteBuffer.allocate(16);
    expected.put("defg".getBytes());

    removeBytesFromStart(bf, 3);

    Assert.assertEquals(expectedCapacity, bf.capacity());
    Assert.assertEquals(0, bf.compareTo(expected));
}

@Test
public void removeBytesFromStartInt() {
    ByteBuffer bf = ByteBuffer.allocate(16);
    int expectedCapacity = bf.capacity();
    bf.putInt(1);
    bf.putInt(2);
    bf.putInt(3);
    bf.putInt(4);

    ByteBuffer expected = ByteBuffer.allocate(16);
    expected.putInt(2);
    expected.putInt(3);
    expected.putInt(4);

    removeBytesFromStart2(bf, 4);

    Assert.assertEquals(expectedCapacity, bf.capacity());
    Assert.assertEquals(0, bf.compareTo(expected));
}

【讨论】:

  • removeBytesFromStart 函数完美运行!感谢您也添加单元测试!
【解决方案2】:

我想你要找的方法是the ByteBuffer's compact() method

即使文档说:

"缓冲区的当前位置和它的限制之间的字节,如果有的话,被复制到缓冲区的开头。也就是说,索引 p = position() 处的字节被复制到索引零,字节索引 p + 1 处的字节被复制到索引 1,依此类推,直到索引 limit() - 1 处的字节被复制到索引 n = limit() - 1 - p。然后将缓冲区的位置设置为 n+1 及其限制设置为其容量。”

我不确定这个方法真的能做到这一点,因为当我调试时,它似乎只是在做buffer.limit = buffer.capacity

【讨论】:

    【解决方案3】:

    您的意思是将所有元素移到缓冲区的开头吗?像这样:

        int n = 4;
        //allocate a buffer of capacity 10 
        ByteBuffer b = ByteBuffer.allocate(10); 
    
        // add data to buffer
        for (int i = 0; i < b.limit(); i++) {
            b.put((byte) i);
        }
    
        // print buffer
        for (int i = 0; i < b.limit(); i++) {
            System.out.print(b.get(i) + " ");
        }
    
        //shift left the elements from the buffer
        //add zeros to the end
        for (int i = n; i < b.limit() + n; i++) {
            if (i < b.limit()) {
                b.put(i - n, b.get(i));
            } else {
                b.put(i - n, (byte) 0);
            }
        }
        //print buffer again
        System.out.println();
        for (int i = 0; i < b.limit(); i++) {
            System.out.print(b.get(i) + " ");
        }
    

    对于 n=4,它将打印:

    0 1 2 3 4 5 6 7 8 9 
    4 5 6 7 8 9 0 0 0 0
    

    【讨论】:

    • 谢谢安德烈!由于解决方案的简洁性,我将 A4L 的答案标记为“正确”。再次感谢!
    • 这个答案避免了从nlimit-n的字节重复写入,对于n &lt; limit/2的情况。
    【解决方案4】:

    为此使用紧凑的方法。例如:

        ByteBuffer b = ByteBuffer.allocate(32);
        b.put("hello,world".getBytes());
        b.position(6);      
        b.compact();
        System.out.println(new String(b.array()));
    

    【讨论】:

      猜你喜欢
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      • 2011-11-13
      • 2013-02-28
      相关资源
      最近更新 更多