2009-09-08 12 views
12

to:Jak zainicjować ByteBuffer, jeśli nie wiesz, ile bajtów należy przeznaczyć wcześniej?

ByteBuffer buf = ByteBuffer.allocate(1000); 

... jedyny sposób zainicjować ByteBuffer?

Co zrobić, jeśli nie mam pojęcia, ile bajtów muszę przydzielić ..?

EDIT: Więcej szczegółów:

jestem konwersja formatu jeden obraz do pliku TIFF. Problem polega na tym, że wyjściowy format pliku może mieć dowolny rozmiar, ale muszę zapisać dane w pliku TIFF do małego endianu. Tak więc najpierw czytam rzeczy, które ostatecznie zamierzam wydrukować do pliku TIFF do ByteBuffer, więc mogę umieścić wszystko w Little Endian, a potem zapiszę to na outfile. Sądzę, że skoro wiem, jak długie są IFD, nagłówki i prawdopodobnie odgadnę, ile bajtów w każdej płaszczyźnie obrazu, mogę użyć wielu Bajtów Beczek podczas tego całego procesu.

Odpowiedz

7

Zależy.

Biblioteka

Konwersja formatów plików wydaje się być rozwiązany problem dla większości domen problemowych. Na przykład:

  • Batik może transkodować między różnymi formatami graficznymi (w tym TIFF).
  • Apache POI może konwertować między formatami arkuszy biurowych.
  • Flexmark może generować HTML ze Markdown.

Lista jest długa. Pierwsze pytanie powinno brzmieć: "Co może zrobić to zadanie?" library Jeśli wydajność jest rozważana, Twój czas jest prawdopodobnie lepiej spędzony, optymalizując istniejący pakiet w celu spełnienia twoich potrzeb, niż pisząc kolejne narzędzie. (Jako bonus, inni dostać się do korzystania z centralnego pracy.)


Znane Ilości

  • Odczyt pliku? Przydziel file.size() bajtów.
  • Kopiowanie ciągu znaków? Przydziel string.length() bajtów.
  • Kopiowanie pakietu TCP? Na przykład przydziel 1500 bajtów.

niewiadomych

Gdy liczba bajtów jest naprawdę nieznana, można zrobić kilka rzeczy:

  • zgadnąć.
  • Analizowanie przykładowych zestawów danych do bufora; użyj średniej długości.

Przykład

Java StringBuffer, chyba że instrukcja mówi inaczej, wykorzystuje początkowy rozmiar bufora do przechowywania 16 znaków. Po wypełnieniu 16 znaków przydzielana jest nowa, dłuższa tablica, a następnie kopiowane są oryginalne 16 znaków. Jeśli rozmiar StringBuffer ma początkowy rozmiar 1024 znaki, to realokacja nie nastąpi tak wcześnie ani tak często.

Optymalizacja

Tak czy inaczej, jest to prawdopodobnie przedwczesna optymalizacja. Zazwyczaj można przydzielić określoną liczbę bajtów, aby zmniejszyć liczbę ponownych przydziałów pamięci wewnętrznej, które zostaną wykonane.

Jest mało prawdopodobne, że będzie to wąskie gardło aplikacji.

+3

" StringBuffer "zachowuje się inaczej. 'ByteBuffer' po prostu rzucił' BufferOverflowException', jeśli spróbujesz dodać więcej. – bvdb

4

Chodzi o to, że to tylko bufor - a nie całość danych. Jest to tymczasowe miejsce do przechowywania danych podczas czytania fragmentu, jego przetwarzania (ewentualnie zapisywania go w innym miejscu). Przydziel sobie wystarczająco dużą "porcję" i zwykle nie będzie problemu.

Na jaki problem się spodziewasz?

10

Typy miejsc, w których można użyć numeru ByteBuffer, to zazwyczaj typy miejsc, w których w przeciwnym razie można użyć tablicy bajtów (która ma również stały rozmiar). W przypadku synchronicznych operacji wejścia/wyjścia często używa się tablic bajtowych, natomiast w przypadku asynchronicznych operacji we/wy używane są ByteBuffers.

Jeśli trzeba czytać nieznaną ilość danych przy użyciu ByteBuffer, należy rozważyć użycie pętlę ze swoim buforze i dołączyć dane do ByteArrayOutputStream jak go odczytać. Kiedy skończysz, zadzwoń pod numer toByteArray(), aby uzyskać ostateczną tablicę bajtów.

Za każdym razem, gdy nie jesteś absolutnie pewny rozmiaru (lub maksymalnego rozmiaru) danego wejścia, odczytywanie w pętli (prawdopodobnie przy użyciu ByteArrayOutputStream, ale poza tym przetwarzanie danych w postaci strumienia, ponieważ jest odczytywane) jest jedynym sposobem, aby sobie z tym poradzić. Bez jakiejś pętli wszystkie pozostałe dane zostaną oczywiście utracone.

Na przykład:

final byte[] buf = new byte[4096]; 
int numRead; 

// Use try-with-resources to auto-close streams. 
try(
    final FileInputStream fis = new FileInputStream(...); 
    final ByteArrayOutputStream baos = new ByteArrayOutputStream() 
) { 
    while ((numRead = fis.read(buf)) > 0) { 
    baos.write(buf, 0, numRead); 
    } 

    final byte[] allBytes = baos.toByteArray(); 

    // Do something with the data. 
} 
catch(final Exception e) { 
    // Do something on failure... 
} 

Jeśli zamiast chciałem napisać Javy int S lub inne rzeczy, które nie są surowe bajty, można owinąć ByteArrayOutputStream w sposób DataOutputStream:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
DataOutputStream dos = new DataOutputStream(baos); 

while (thereAreMoreIntsFromSomewhere()) { 
    int someInt = getIntFromSomewhere(); 
    dos.writeInt(someInt); 
} 

byte[] allBytes = baos.toByteArray();  
+0

Czy możesz podać przykład tego za pomocą ByteArrayOutputStream? Jak na przykład powiedzmy o liczbę całkowitą? –

+0

@PaulaKristin Sprawdź teraz (Naprawiłem również uszkodzony link 'ByteArrayOutputStream') –