将字节从一个ByteBuffer传输到另一个ByteBuffer

8
什么是从ByteBuffer bbuf_src 尽可能多地放置字节到另一个ByteBuffer bbuf_dest 的最有效方法(以及知道传输了多少字节)?我试图使用 bbuf_dest.put(bbuf_src),但它似乎想要抛出BufferOverflowException,并且当我需要它们时,我现在无法获得Sun的javadoc(网络问题)。 >:( 噫。
编辑:该死,@Richard的方法(使用来自 bbuf_src 的支持数组的put())如果bbuf_src是只读缓冲区,则不起作用,因为您无法访问该数组。在这种情况下我该怎么办?

我认为你应该将这个问题分成两个。 - GEOCHET
请仅返回翻译后的文本:另一半已转移到此处:https://dev59.com/M0bRa4cB1Zd3GeqP2KKY - Jason S
3个回答

11

如你所发现的那样,获取支持数组并不总是可行的(对于只读缓冲区、直接缓冲区和内存映射文件缓冲区会失败)。更好的选择是复制源缓冲区并设置新的限制以传输所需数据量:

int maxTransfer = Math.min(bbuf_dest.remaining(), bbuf_src.remaining());
// use a duplicated buffer so we don't disrupt the limit of the original buffer
ByteBuffer bbuf_tmp = bbuf_src.duplicate ();
bbuf_tmp.limit (bbuf_tmp.position() + maxTransfer);
bbuf_dest.put (bbuf_tmp);

// now discard the data we've copied from the original source (optional)
bbuf_src.position(bbuf_src.position() + maxTransfer);

但是Oracle表示限制必须“不大于缓冲区的容量”。复制缓冲区将复制其容量,不是吗? - Jorge Fuentes González
我知道这是一个旧答案,但为什么要复制源缓冲区而不是只存储旧的限制,并在put操作后恢复它呢? - Wisteso
@Wisteso - 你可以这样做,这可能会稍微更有效率一些(虽然不是很多,所以在大多数情况下都不太重要),但我认为复制缓冲区更容易。而且更难出错(例如忘记恢复之后)。 - Jules
1
@Jules 谢谢您的反馈。我已经修改了我的代码以保存/恢复限制,现在它运行得非常好。由于吞吐量非常高且GC负担很大,我不想重复它。我还需要对“位置”的更改进行永久性修改。 - Wisteso

2

好的,我已经改编了@Richard的回答:

public static int transferAsMuchAsPossible(
                     ByteBuffer bbuf_dest, ByteBuffer bbuf_src)
{
  int nTransfer = Math.min(bbuf_dest.remaining(), bbuf_src.remaining());
  if (nTransfer > 0)
  {
    bbuf_dest.put(bbuf_src.array(), 
                  bbuf_src.arrayOffset()+bbuf_src.position(), 
                  nTransfer);
    bbuf_src.position(bbuf_src.position()+nTransfer);
  }
  return nTransfer;
}

并且需要进行测试以确保其正常工作:

public static boolean transferTest()
{
    ByteBuffer bb1 = ByteBuffer.allocate(256);
    ByteBuffer bb2 = ByteBuffer.allocate(50);
    for (int i = 0; i < 100; ++i)
    {
        bb1.put((byte)i);
    }
    bb1.flip();
    bb1.position(5);
    ByteBuffer bb1a = bb1.slice();
    bb1a.position(2);
    // bb3 includes the 5-100 range
    bb2.put((byte)77);
    // something to see this works when bb2 isn't empty
    int n = transferAsMuchAsPossible(bb2, bb1a);
    boolean itWorked = (n == 49);

    if (bb1a.position() != 51)
        itWorked = false;
    if (bb2.position() != 50)
        itWorked = false;
    bb2.rewind();
    if (bb2.get() != 77)
        itWorked = false;
    for (int i = 0; i < 49; ++i)
    {
        if (bb2.get() != i+7)
        {
            itWorked = false;
            break;
        }
    }
    return itWorked;
}

这种方法无法用于从只读的 ByteBuffer 中复制,因为 .array() 不被允许(在 Java 中没有只读数组这样的东西)。 - Laurence Gonsalves

0

你会收到BufferOverflowException异常,因为你的bbuf_dest不够大。

你需要使用bbuf_dest.remaining()来找出你可以从bbuf_src传输的最大字节数:

int maxTransfer = Math.min(bbuf_dest.remaining(), bbuf_src.remaining());
bbuf_dest.put(bbuf_src.array(), 0, maxTransfer);

啊,很有帮助。我现在知道该怎么做了。谢谢。但需要注意的是,如果bbuf_src是另一个缓冲区的视图缓冲区,则您的答案将无效。不过我认为我可以适应它。 - Jason S
(或者如果bbuf_src的位置大于0) - Jason S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接