2010-07-29 43 views
20

java.nio.ByteBuffer#duplicate() restituisce un nuovo buffer di byte che condivide il contenuto del vecchio buffer. Le modifiche al contenuto del vecchio buffer saranno visibili nel nuovo buffer e viceversa. Cosa succede se voglio una copia profonda del buffer dei byte?profonda duplice copia() di ByteBuffer di Java

risposta

1

Avrai bisogno di iterare l'intero buffer e copiare dal valore nel nuovo buffer.

+3

C'è un (opzionale) overload del metodo 'PUT' che fa questo per voi però. – nos

+0

Woohoo! Ho imparato qualcosa di nuovo. – Kylar

35

penso che la copia completa non deve coinvolgere byte[]. Provare quanto segue:

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

Perché devo capovolgere il clone? Quindi il limite è inferiore alla mia reale capacità – Karussell

+0

WOW! È stato utile. –

+2

L'unica cosa non copiata in questo caso è il marchio, quindi sappi solo che se usi il segno verrà perso. Inoltre, questa funzione copia solo dall'inizio al limite e la posizione del originale è perso, vorrei suggerire posizione = 0 e il limite = capacità di impostazione e la loro memorizzazione come temperatura vars essere ripristinato in originale e il clone prima di tornare. Anche riavvolgere scarta il segno, quindi non è una buona idea utilizzarlo. Pubblicherò una risposta con un metodo più completo. – LINEMAN78

2

base al largo della soluzione di mingfai:

Questo vi darà quasi copia profonda. L'unica cosa persa sarà il marchio. Se orig è un HeapBuffer e l'offset non è zero o la capacità è inferiore all'array di supporto rispetto ai dati esterni non copiati.

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

Perché è necessario verificare il nome della classe quando 'Buffer # isDirect()' è disponibile pubblicamente? – seh

+0

Buon punto, ho dimenticato questo metodo. Aggiornerà. – LINEMAN78

15

Come questa domanda viene ancora come uno dei primi colpi per la copia di un ByteBuffer, offrirò la mia soluzione. Questa soluzione non tocca il buffer originale, compresi eventuali contrassegni, e restituirà una copia profonda con la stessa capacità dell'originale.

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

Se si preoccupa per la posizione, limite, o per impostare la stessa come l'originale, allora questo è un facile aggiunta a quanto sopra:

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

Perché non 'clone.put (readOnlyCopy)' al posto della matrice intermedia 'byte'? – seh

+0

@seh Perché ero stupido e non ho visto quel metodo. Grazie per segnalarlo. – jdmichal

+0

Questa è la soluzione migliore. Non muta i contenuti originali e fornisce i modi più puliti per fare la stessa cosa. –

2

più Una soluzione semplice

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