Java的ByteBuffer的深拷贝重复()

问题描述:

java.nio.ByteBuffer#duplicate()返回共享旧缓冲区内容的新字节缓冲区。旧缓冲区内容的更改将在新缓冲区中可见,反之亦然。如果我想要一个字节缓冲区的深层副本,该怎么办?Java的ByteBuffer的深拷贝重复()

您需要迭代整个缓冲区并按值复制到新缓冲区中。

+3

有一个(可选的)“put”方法的重载,它可以为你做到这一点。 – nos 2010-07-29 21:08:02

+0

呜呼!我学到了一些新东西。 – Kylar 2010-07-29 22:11:25

我认为深拷贝不需要涉及byte[]。请尝试以下操作:基于关mingfai解决方案的

public static ByteBuffer clone(ByteBuffer original) { 
     ByteBuffer clone = ByteBuffer.allocate(original.capacity()); 
     original.rewind();//copy from the beginning 
     clone.put(original); 
     original.rewind(); 
     clone.flip(); 
     return clone; 
} 
+0

为什么我需要翻转克隆?那么这个限制低于我的实际容量 – Karussell 2012-06-16 13:23:14

+0

WOW!这很有帮助。 – 2012-08-31 14:54:20

+2

在这种情况下不复制的唯一东西是标记,所以只要知道如果使用标记它将会丢失。此外,该功能只能从开始到极限复制,并且原稿的位置丢失,我建议设置position = 0和limit = capacity,并将它们存储为临时变量,并在返回前复位原始和克隆。还倒退丢弃标记,所以使用这可能不是一个好主意。我会用更完整的方法发布答案。 – LINEMAN78 2012-11-20 03:01:08

这会给你一个几乎真实的深层复制。唯一失去的将是标记。如果orig是HeapBuffer,并且偏移量不为零或者容量小于后备数组,则不会复制远端数据。

public static ByteBuffer deepCopy(ByteBuffer orig) 
{ 
    int pos = orig.position(), lim = orig.limit(); 
    try 
    { 
     orig.position(0).limit(orig.capacity()); // set range to entire buffer 
     ByteBuffer toReturn = deepCopyVisible(orig); // deep copy range 
     toReturn.position(pos).limit(lim); // set range to original 
     return toReturn; 
    } 
    finally // do in finally in case something goes wrong we don't bork the orig 
    { 
     orig.position(pos).limit(lim); // restore original 
    } 
} 

public static ByteBuffer deepCopyVisible(ByteBuffer orig) 
{ 
    int pos = orig.position(); 
    try 
    { 
     ByteBuffer toReturn; 
     // try to maintain implementation to keep performance 
     if(orig.isDirect()) 
      toReturn = ByteBuffer.allocateDirect(orig.remaining()); 
     else 
      toReturn = ByteBuffer.allocate(orig.remaining()); 

     toReturn.put(orig); 
     toReturn.order(orig.order()); 

     return (ByteBuffer) toReturn.position(0); 
    } 
    finally 
    { 
     orig.position(pos); 
    } 
} 
+0

当'Buffer#isDirect()'公开可用时,为什么需要类名检查? – seh 2012-11-20 15:50:06

+0

好点,忘了那个方法。将更新。 – LINEMAN78 2012-11-21 02:04:07

由于这个问题仍然出现作为第一命中一个复制ByteBuffer,我会提供我的解决方案。此解决方案不会触及原始缓冲区(包括任何标记集),并会返回具有与原始相同容量的深层副本。

public static ByteBuffer cloneByteBuffer(final ByteBuffer original) { 
    // Create clone with same capacity as original. 
    final ByteBuffer clone = (original.isDirect()) ? 
     ByteBuffer.allocateDirect(original.capacity()) : 
     ByteBuffer.allocate(original.capacity()); 

    // Create a read-only copy of the original. 
    // This allows reading from the original without modifying it. 
    final ByteBuffer readOnlyCopy = original.asReadOnlyBuffer(); 

    // Flip and read from the original. 
    readOnlyCopy.flip(); 
    clone.put(readOnlyCopy); 

    return clone; 
} 

如果一个关心的位置,限制,或为了设置的原来一样的,那么这是一个简单的除上述:

clone.position(original.position()); 
clone.limit(original.limit()); 
clone.order(original.order()); 
return clone; 
+1

为什么'clone.put(readOnlyCopy)'而不是中间的'byte'数组? – seh 2014-01-27 19:34:57

+0

@seh因为我很傻,没有看到这种方法。感谢您指出。 – jdmichal 2014-01-27 19:43:47

+0

这是最好的解决方案。它不会改变原始内容,并提供最干净的方式来做同样的事情。 – 2014-10-19 01:29:31

一种更简单的解决方案

public ByteBuffer deepCopy(ByteBuffer source, ByteBuffer target) { 

    int sourceP = source.position(); 
    int sourceL = source.limit(); 

    if (null == target) { 
     target = ByteBuffer.allocate(source.remaining()); 
    } 
    target.put(source); 
    target.flip(); 

    source.position(sourceP); 
    source.limit(sourceL); 
    return target; 
}