2010-07-29 5 views
20

java.nio.ByteBuffer#duplicate() возвращает новый байтовый буфер, который разделяет содержимое старого буфера. Изменения в содержимом старого буфера будут видны в новом буфере и наоборот. Что делать, если я хочу получить глубокую копию байтового буфера?Глубокая копия() Java ByteBuffer

ответ

1

Вам нужно будет перебрать весь буфер и скопировать по значению в новый буфер.

+3

Существует (необязательная) перегрузка метода 'put', который делает это для вас. – nos

+0

Woohoo! Я узнал что-то новое. – Kylar

35

Я думаю, что глубокая копия не обязательно должна включать byte[]. Попробуйте следующее:

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

+0

WOW! Это было полезно. –

+2

Единственное, что не копируется в этом случае, это знак, поэтому просто знайте, что если вы используете знак, он будет потерян. Кроме того, эта функция только копирует от начала до предела, а позиция оригинала теряется, я бы предложил установить положение = 0 и limit = емкость и сохранить их как временные вары, которые будут сброшены на оригинал и клон перед возвратом. Кроме того, перемотка назад отбрасывает метку, поэтому использование, вероятно, не очень хорошая идея. Я отправлю ответ с более полным методом. – LINEMAN78

2

Основы раствора mingfai в:

Это даст вам почти настоящую глубокую копию. Единственное, что потеряно, - это знак. Если 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

+0

Хороший вопрос, забыл об этом методе. Будет обновляться. – LINEMAN78

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

+0

@seh Потому что я был глупым и не видел этого метода. Спасибо, что указали это. – jdmichal

+0

Это лучшее решение. Он не мутирует исходное содержимое и обеспечивает самые чистые способы сделать то же самое. –

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; 
} 
Смежные вопросы