2010-07-29 23 views
20

java.nio.ByteBuffer#duplicate() devuelve un nuevo búfer de bytes que comparte el contenido del búfer antiguo. Los cambios en el contenido del viejo buffer serán visibles en el nuevo buffer, y viceversa. ¿Qué pasa si quiero una copia profunda del buffer de byte?Copia profunda duplicada() de ByteBuffer de Java

Respuesta

1

Tendrá que iterar todo el almacenamiento intermedio y copiar por valor en el nuevo almacenamiento intermedio.

+3

Hay una sobrecarga (opcional) del método 'put' que hace esto por usted. – nos

+0

Woohoo! Aprendí algo nuevo. – Kylar

35

Creo que la copia profunda no necesita involucrar a byte[]. Pruebe lo siguiente:

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

¿Por qué necesito voltear el clon? Entonces el límite es más bajo que mi capacidad real – Karussell

+0

¡GUAU! Eso fue útil. ¡Gracias! –

+2

Lo único que no se copia en este caso es la marca, así que tenga en cuenta que si usa la marca, se perderá. Además, esta función solo copia desde el principio hasta el límite y la posición del original se pierde; sugiero que se establezca position = 0 y limit = capacity y que se almacenen como temps temporales para restablecer en el original y clonar antes de regresar. También rebobinar descarta la marca, por lo que usar eso probablemente no sea una buena idea. Voy a publicar una respuesta con un método más completo. – LINEMAN78

2

base fuera de la solución de mingfai:

Esto le dará una copia casi verdad profunda. Lo único perdido será la marca. Si orig es un HeapBuffer y el desplazamiento no es cero o la capacidad es inferior a la matriz de respaldo que los datos periféricos no se copian.

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

¿Por qué necesita la verificación de nombre de clase cuando 'Buffer # isDirect()' está disponible públicamente? – seh

+0

Buen punto, se olvidó de ese método. Actualizará. – LINEMAN78

15

Como esta pregunta todavía aparece como uno de los primeros éxitos de la copia de un ByteBuffer, ofreceré mi solución. Esta solución no toca el búfer original, incluido ningún conjunto de marcas, y devolverá una copia profunda con la misma capacidad que el original.

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

Si uno se preocupa por la posición, límite, o con el fin de ajustar el mismo que el original, entonces eso es una adición fácil de lo anterior:

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

¿Por qué no 'clone.put (readOnlyCopy)' en lugar de la matriz intermedia 'byte'? – seh

+0

@seh Porque era tonto y no vi ese método. Gracias por mencionarlo. – jdmichal

+0

Esta es la mejor solución. No muta el contenido original y proporciona las formas más limpias de hacer lo mismo. –

2

Uno más solución simple

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