Chciałbym przekonwertować tablicę znaków na tablicę bajtów w Javie. Jakie są metody dokonywania tej konwersji?
java
arrays
type-conversion
Arun Abraham
źródło
źródło
Konwertuj bez tworzenia
String
obiektu:import java.nio.CharBuffer; import java.nio.ByteBuffer; import java.util.Arrays; byte[] toBytes(char[] chars) { CharBuffer charBuffer = CharBuffer.wrap(chars); ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer); byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit()); Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data return bytes; }
Stosowanie:
char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; byte[] bytes = toBytes(chars); /* do something with chars/bytes */ Arrays.fill(chars, '\u0000'); // clear sensitive data Arrays.fill(bytes, (byte) 0); // clear sensitive data
Rozwiązanie zostało zainspirowane zaleceniem Swing dotyczącym przechowywania haseł w char []. (Zobacz Dlaczego hasła char [] są preferowane zamiast ciągów znaków? )
Pamiętaj, aby nie zapisywać wrażliwych danych w dziennikach i upewnij się, że JVM nie będzie zawierał żadnych odniesień do nich.
Powyższy kod jest poprawny, ale nieskuteczny. Jeśli nie potrzebujesz wydajności, ale chcesz bezpieczeństwa, możesz go użyć. Jeśli bezpieczeństwo również nie jest celem, zrób to po prostu
String.getBytes
. Powyższy kod nie jest skuteczny, jeśli spojrzysz na implementacjęencode
w JDK. Poza tym musisz kopiować tablice i tworzyć bufory. Innym sposobem konwersji jest wbudowany cały kod zaencode
(na przykład dla UTF-8 ):val xs: Array[Char] = "A ß € 嗨 𝄞 🙂".toArray val len = xs.length val ys: Array[Byte] = new Array(3 * len) // worst case var i = 0; var j = 0 // i for chars; j for bytes while (i < len) { // fill ys with bytes val c = xs(i) if (c < 0x80) { ys(j) = c.toByte i = i + 1 j = j + 1 } else if (c < 0x800) { ys(j) = (0xc0 | (c >> 6)).toByte ys(j + 1) = (0x80 | (c & 0x3f)).toByte i = i + 1 j = j + 2 } else if (Character.isHighSurrogate(c)) { if (len - i < 2) throw new Exception("overflow") val d = xs(i + 1) val uc: Int = if (Character.isLowSurrogate(d)) { Character.toCodePoint(c, d) } else { throw new Exception("malformed") } ys(j) = (0xf0 | ((uc >> 18))).toByte ys(j + 1) = (0x80 | ((uc >> 12) & 0x3f)).toByte ys(j + 2) = (0x80 | ((uc >> 6) & 0x3f)).toByte ys(j + 3) = (0x80 | (uc & 0x3f)).toByte i = i + 2 // 2 chars j = j + 4 } else if (Character.isLowSurrogate(c)) { throw new Exception("malformed") } else { ys(j) = (0xe0 | (c >> 12)).toByte ys(j + 1) = (0x80 | ((c >> 6) & 0x3f)).toByte ys(j + 2) = (0x80 | (c & 0x3f)).toByte i = i + 1 j = j + 3 } } // check println(new String(ys, 0, j, "UTF-8"))
Przepraszam za używanie języka Scala. Jeśli masz problemy z konwersją tego kodu do Java mogę go przepisać. A co z wydajnością, zawsze sprawdzaj rzeczywiste dane (na przykład z JMH). Ten kod wygląda bardzo podobnie do tego, co można zobaczyć w JDK [ 2 ] i Protobuf [ 3 ].
źródło
Edycja: odpowiedź Andreya została zaktualizowana, więc poniższe nie mają już zastosowania.
Odpowiedź Andreya (najwięcej głosów w momencie pisania) jest nieco niepoprawna. Dodałbym to jako komentarz, ale nie mam wystarczającej reputacji.
W odpowiedzi Andreya:
char[] chars = {'c', 'h', 'a', 'r', 's'} byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();
wywołanie funkcji array () może nie zwrócić żądanej wartości, na przykład:
char[] c = "aaaaaaaaaa".toCharArray(); System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));
wynik:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]
Jak widać, dodano bajt zerowy. Aby tego uniknąć, użyj następujących:
char[] c = "aaaaaaaaaa".toCharArray(); ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c)); byte[] b = new byte[bb.remaining()]; bb.get(b); System.out.println(Arrays.toString(b));
wynik:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]
Ponieważ odpowiedź dotyczyła również używania haseł, warto wyczyścić tablicę, która obsługuje ByteBuffer (dostęp do niej uzyskuje się za pośrednictwem funkcji array ()):
ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c)); byte[] b = new byte[bb.remaining()]; bb.get(b); blankOutByteArray(bb.array()); System.out.println(Arrays.toString(b));
źródło
averageBytesPerChar()
zwróci cokolwiek innego niż 1 (otrzymam 1.1). Nie interesuje mnie, jakiego systemu operacyjnego / arch używasz, gdy dwukrotnie sprawdziłem z oracle 1.7.0_51 i openjdk 1.7.0_51 i stwierdziłem, że jest uszkodzony z 10 znakami.buffer.array()
wtoBytes
funkcji nadal musi zostać zastąpiona, obecnie jest tylko kopia.private static byte[] charArrayToByteArray(char[] c_array) { byte[] b_array = new byte[c_array.length]; for(int i= 0; i < c_array.length; i++) { b_array[i] = (byte)(0xFF & (int)c_array[i]); } return b_array; }
źródło
Możesz stworzyć metodę:
public byte[] toBytes(char[] data) { byte[] toRet = new byte[data.length]; for(int i = 0; i < toRet.length; i++) { toRet[i] = (byte) data[i]; } return toRet; }
Mam nadzieję że to pomoże
źródło