2010-07-29 10 views
20

java.nio.ByteBuffer#duplicate() zwraca nowy bufor bajtowy, który udostępnia zawartość starego bufora. Zmiany w zawartości starego bufora będą widoczne w nowym buforze i na odwrót. Co się stanie, jeśli chcę mieć głęboką kopię bufora bajtowego?Duplikat kopii głębokiej() Javy ByteBuffer

Odpowiedz

1

Będziesz musiał powtórzyć cały bufor i skopiować według wartości do nowego bufora.

+3

Istnieje (opcjonalne) przeciążenie metody 'put', która robi to za Ciebie. – nos

+0

Woohoo! Nauczyłem się czegoś nowego. – Kylar

35

Myślę, że kopia nie musi zawierać byte[]. Spróbuj wykonać następujące czynności:

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

Dlaczego muszę odwrócić klon? Wtedy limit jest niższy niż moja prawdziwa pojemność – Karussell

+0

WOW! To było pomocne. Dzięki! –

+2

Jedyną rzeczą, która nie została skopiowana w tym przypadku, jest znak, więc po prostu wiedz, że jeśli użyjesz znaku, zostanie utracone. Ponadto ta funkcja kopiuje tylko od początku do limitu, a pozycja oryginału jest tracona, sugerowałbym ustawienie position = 0 i limit = capacity i przechowywanie ich jako zmiennych tymczasowych, które mają być zresetowane na oryginale i sklonowane przed powrotem. Również przewijanie odrzuca znak, więc użycie tego prawdopodobnie nie jest dobrym pomysłem. Opublikuję odpowiedź bardziej kompletną metodą. – LINEMAN78

2

oparciu off roztworu mingfai za:

To daje prawie prawdziwą głęboką kopię. Jedyną rzeczą utraconą będzie znak. Jeśli orig jest HeapBuffer, a offset nie jest równy zeru lub pojemność jest mniejsza niż tablica backingowa, niż nie są kopiowane odległe dane.

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

Dlaczego potrzebne jest sprawdzenie nazwy klasy, gdy 'Buffer # isDirect()' jest dostępny publicznie? – seh

+0

Dobra uwaga, zapomniałem o tej metodzie. Zaktualizuję. – LINEMAN78

15

Ponieważ kwestia ta nadal pojawia się jako jeden z pierwszych hitów do kopiowania ByteBuffer, złożę moje rozwiązanie. To rozwiązanie nie dotyka oryginalnego bufora, w tym żadnego zestawu znaczników, i zwróci głęboką kopię o takiej samej pojemności, jak oryginał.

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

Jeśli dba o położeniu, ogranicza, lub aby być ustawione tak samo, jak w oryginale, to jest to łatwe, oprócz wyżej wymienionych:

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

Dlaczego nie 'clone.put (readOnlyCopy)' zamiast pośredniej tablicy 'byte'? – seh

+0

@seh Ponieważ byłem głupi i nie widziałem tej metody. Dziękuję za wskazanie. – jdmichal

+0

To jest najlepsze rozwiązanie. Nie modyfikuje oryginalnej zawartości i zapewnia najczystsze sposoby robienia tego samego. –

2

jedno proste rozwiązanie

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