2010-07-29 4 views
20

java.nio.ByteBuffer#duplicate() Renvoie un nouveau tampon d'octets qui partage le contenu de l'ancien tampon. Les modifications apportées au contenu de l'ancien tampon seront visibles dans le nouveau tampon, et vice versa. Que faire si je veux une copie profonde du tampon d'octets?Copie en profondeur duplicate() de ByteBuffer Java

Répondre

1

Vous aurez besoin d'itérer toute la mémoire tampon et de la copier par valeur dans le nouveau tampon.

+3

Il y a une surcharge (optionnelle) de la méthode 'put' qui fait cela pour vous. – nos

+0

Woohoo! J'ai appris quelque chose de nouveau. – Kylar

35

Je pense que la copie profonde ne doit pas impliquer byte[]. Effectuez les actions suivantes:

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

Pourquoi ai-je besoin de retourner le clone? Ensuite, la limite est inférieure à ma capacité réelle – Karussell

+0

WOW! C'était utile.THanks! –

+2

La seule chose qui n'est pas copiée dans ce cas est la marque, alors sachez que si vous utilisez marque, elle sera perdue. De plus, cette fonction copie seulement du début à la limite et la position de l'original est perdue, je suggérerais de mettre position = 0 et limit = capacité et de les stocker comme temp vars à réinitialiser sur original et cloner avant de revenir. Le rembobinage supprime également la marque, ce qui n'est probablement pas une bonne idée. Je posterai une réponse avec une méthode plus complète. – LINEMAN78

2

Basé hors de la solution de mingfai:

Cela vous donnera une copie en profondeur presque vrai. La seule chose perdue sera la marque. Si orig est un HeapBuffer et que le décalage n'est pas égal à zéro ou que la capacité est inférieure au tableau de sauvegarde, les données périphériques ne sont pas copiées.

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

Pourquoi avez-vous besoin de la vérification du nom de classe lorsque 'Buffer # isDirect()' est disponible publiquement? – seh

+0

Bon point, j'ai oublié cette méthode. Mettra à jour. – LINEMAN78

15

Cette question est encore comme l'un des premiers coups à la copie d'un ByteBuffer, je proposerai ma solution. Cette solution ne touche pas le tampon d'origine, y compris les marques définies, et renvoie une copie profonde avec la même capacité que l'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 l'on prend soin de la position, limite, ou pour régler le même que l'original, alors c'est un ajout facile au-dessus:

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

Pourquoi pas 'clone.put (readOnlyCopy)' au lieu du tableau intermédiaire 'byte'? – seh

+0

@seh Parce que j'étais stupide et n'ai pas vu cette méthode. Merci de l'avoir signalé. – jdmichal

+0

C'est la meilleure solution. Il ne mute pas le contenu original et fournit les moyens les plus propres de faire la même chose. –

2

Encore une solution 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; 
} 
Questions connexes