2009-10-19 14 views
5

Czytam 8 bajtów danych z urządzenia sprzętowego. Muszę przekształcić je w wartość liczbową. Myślę, że chcę je przekonwertować na długi, ponieważ powinien zmieścić 8 bajtów. Nie jestem zaznajomiony z Javą i niskopoziomowymi operacjami typu danych. Wydaje mi się, że mam dwa problemy (poza faktem, że prawie nie ma dokumentacji dla danego sprzętu), bajty oczekują, że będą niepodpisane, więc nie mogę przeprowadzić prostej konwersji całkowitej. Nie jestem pewien, jaka to endaniczność.Jak przekonwertować bajt na długi w Javie?

Każda rada byłaby doceniona.


skończyło się to (wzięte z jakiegoś kodu źródłowego pewnie powinien przeczytać tydzień temu):

public static final long toLong (byte[] byteArray, int offset, int len) 
{ 
    long val = 0; 
    len = Math.min(len, 8); 
    for (int i = (len - 1); i >= 0; i--) 
    { 
     val <<= 8; 
     val |= (byteArray [offset + i] & 0x00FF); 
    } 
    return val; 
} 
+0

Dlaczego trzeba przekonwertować te 8 bajtów na jedną wartość liczbową? Jeśli rzeczywiście są bajtami składowymi o większej wartości, nie są one ani "podpisane" ani "niepodpisane". Jeśli nie wiesz, czym jest ich endianizm, po prostu nie możesz zinterpretować ich jako długiej wartości. –

+0

Wiem, że są to kolejne wartości (licznik magnetyczny), więc dzięki próbom i błędom mogę stwierdzić, kiedy raportuje poprawną inkrementację. Muszę przekonwertować je na jedną wartość liczbową, aby określić szybkość zmian. – Jotham

+0

Powinieneś zastąpić 0x00FF przez 0xFFL, ponieważ lepiej byłoby wyrazić zamiar konwersji bajtu na długi. – starblue

Odpowiedz

1

Aby uzyskać endianię, przetestuj z pewnymi liczbami, które znasz, a następnie użyjesz przesunięcia bajtów, aby przesunąć je w długi.

Może się okazać, że jest to punkt wyjścia. http://www.janeg.ca/scjp/oper/shift.html

Trudność polega na tym, że w zależności od kolejność bajtów zmieni jak to zrobić, ale trzeba będzie przesunąć o 24, 16, 8, a następnie dodać ostatni, w zasadzie, jeśli robi 32 bity, ale idziesz dłużej, więc po prostu dokonaj dodatkowej zmiany biegów.

+0

z dodatkowym przesunięciem, musisz uważać, że przesuniesz 'long', a nie' int', ponieważ przesuwanie więcej niż 24 bitów w 'int' spowoduje odrzucenie bitów o najwyższej kolejności. – erickson

+0

Stwierdził, że to było długie, więc sądzę, że może określić, ile bitów powinien on być naprawdę potrzebny. –

4

Byte#longValue() powinien to zrobić

a jeśli nie (dzięki dla źródła przykład) możesz użyć java.nio.ByteBuffer, np.

public static long toLong(byte[] b) { 
    ByteBuffer bb = ByteBuffer.allocate(b.length); 
    bb.put(b); 
    return bb.getLong(); 
} 

Początkowa lub der to BIG_ENDIAN, możesz trzcnąć more here

+0

Miałem coś takiego, ale nadal nie było dobrze. Może dlatego, że jestem nowy w Javie. public static long bufferToLong (byte [] b) { \t długa wartość = b [0]; \t dla (int i = 1; i Jotham

+0

Więc po co jest -1? Tak czy inaczej - rozszerzyłem odpowiedź, aby dać ci inny pomysł. Z tego, co wiem - java.nio jest dość szybki (szybciej niż zwykłe strumienie odmiany). – Bostone

+1

Otrzymuję 'BufferUnderflowException' chyba że zadzwonię' bb.flip(); 'zanim zadzwonię' getLong() ' –

1

Zobacz BigInteger (bajt []). To prawie to, czego chcesz, z wyjątkiem tego, że jest podpisany. Możesz dodać do niego jeszcze jeden bajt, zanim przekażesz go do BigInteger.

Inną sprawą jest to, że powinieneś zdawać sobie sprawę z tego, jakie są twoje bajty.

Mam nadzieję, że to pomoże.

12

Przesunięcie bajtów zgodnie z endiansem danych jest dość proste. Istnieje niewielka sztuczka z typem danych long, ponieważ operacja binarna na integralnych typach int lub mniejszych promuje argumenty operacji do int. Dla przesunięć w lewo większych niż 31 bitów, spowoduje to zero, ponieważ wszystkie bity zostały przesunięte poza zakres int.

Więc wymuś promocję na long, włączając w to operanię long w obliczeniach. Poniżej robię to maskując każdy bajt o wartości 0xFF L, która jest long, zmuszając wynik do uzyskania wartości long.

byte[] buf = new byte[8]; 
/* Fill buf somehow... */ 
long l = ((buf[0] & 0xFFL) << 56) | 
     ((buf[1] & 0xFFL) << 48) | 
     ((buf[2] & 0xFFL) << 40) | 
     ((buf[3] & 0xFFL) << 32) | 
     ((buf[4] & 0xFFL) << 24) | 
     ((buf[5] & 0xFFL) << 16) | 
     ((buf[6] & 0xFFL) << 8) | 
     ((buf[7] & 0xFFL) << 0) ; 
+0

Być może zechcesz zamieścić kilka odlewów na długo ... –

+0

A może użyjesz indeksu tablicowego innego niż 0. –

+0

Tak, zauważyłem to podczas komentowania ... Zająłem się tym, promując na długo w maskowanie. – erickson

5

Uważam, że można skorzystać z java.nio. W ten sposób można zapisać 8 bajtów w długi:

// Byte Array TO Long 
public static long batol(byte[] buff) { 
    return batol(buff, false); 
} 

public static long batol(byte[] buff, boolean littleEndian) { 
    assert(buff.length == 8); 
    ByteBuffer bb = ByteBuffer.wrap(buff); 
    if (littleEndian) bb.order(ByteOrder.LITTLE_ENDIAN); 
    return bb.getLong(); 
}

Oczywiście, powstałe tęskni będzie podpisali oświadczenie, ale będą one miały identyczne wartości binarnych do danych źródłowych.Dla 64 bitowego + unsigned reprezentacji i arithmatic, musisz użyć BigInteger. Oto jak przekonwertować z „bez znaku” danych zapisanych w długi do prawidłowego BigInteger:

// "Unsigned" Long TO Big Integer 
public static BigInteger ultobi(long ul) { 
    byte[] buff = new byte[8]; 
    ByteBuffer.wrap(buff).asLongBuffer().put(ul); 
    return new BigInteger(+1, buff); 
}
Powiązane problemy