2010-07-29 120 views
20

java.nio.ByteBuffer#duplicate()返回共享舊緩衝區內容的新字節緩衝區。舊緩衝區內容的更改將在新緩衝區中可見,反之亦然。如果我想要一個字節緩衝區的深層副本,該怎麼辦?Java的ByteBuffer的深拷貝重複()

回答

1

您需要迭代整個緩衝區並按值複製到新緩衝區中。

+3

有一個(可選的)「put」方法的重載,它可以爲你做到這一點。 – nos 2010-07-29 21:08:02

+0

嗚呼!我學到了一些新東西。 – Kylar 2010-07-29 22:11:25

35

我認爲深拷貝不需要涉及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

2

這會給你一個幾乎真實的深層複製。唯一失去的將是標記。如果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

15

由於這個問題仍然出現作爲第一命中一個複製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

2

一種更簡單的解決方案

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; 
}