Массив байтов в строку и обратно .. проблемы с -127 - PullRequest
31 голосов
/ 09 марта 2011

В следующем:

 scala> (new String(Array[Byte](1, 2, 3, -1, -2, -127))).getBytes
 res12: Array[Byte] = Array(1, 2, 3, -1, -2, 63)

почему -127 преобразуется в 63? и как мне вернуть его как -127

[РЕДАКТИРОВАТЬ:] Java-версия ниже (чтобы показать, что это не просто «проблема Scala»)

c:\tmp>type Main.java
public class Main {
    public static void main(String [] args) {
        byte [] b = {1, 2, 3, -1, -2, -127};
        byte [] c = new String(b).getBytes();
        for (int i = 0; i < 6; i++){
            System.out.println("b:"+b[i]+"; c:"+c[i]);
        }
    }
}
c:\tmp>javac Main.java
c:\tmp>java Main
b:1; c:1
b:2; c:2
b:3; c:3
b:-1; c:-1
b:-2; c:-2
b:-127; c:63

Ответы [ 4 ]

50 голосов
/ 09 марта 2011

Конструктор, который вы вызываете, делает неочевидным, что двоичные преобразования в строки используют декодирование: String(byte[] bytes, Charset charset). То, что вы хотите, это вообще не использовать декодирование.

К счастью, для этого есть конструктор: String(char[] value).

Теперь у вас есть данные в виде строки, но вы хотите вернуть их точно так же, как есть. Но угадайте что! getBytes(Charset charset) Правильно, автоматически применяется и кодировка. К счастью, есть метод toCharArray().

Если вы должны начинать с байтов и заканчивать байтами, вам необходимо сопоставить массивы символов с байтами:

(new String(Array[Byte](1,2,3,-1,-2,-127).map(_.toChar))).toCharArray.map(_.toByte)

Итак, подведем итог: преобразование между String и Array[Byte] включает в себя кодирование и декодирование. Если вы хотите поместить двоичные данные в строку, вы должны сделать это на уровне символов. Обратите внимание, однако, что это даст вам строку мусора (то есть результат не будет правильно сформирован UTF-16, как ожидается String), и поэтому вам лучше прочитать его как символы и преобразовать его обратно в байты.

Вы могли бы сдвинуть байты, скажем, добавив 512; тогда вы получите кучу действительных Char кодовых точек. Но это использует 16 бит для представления каждых 8, 50% эффективности кодирования. Base64 - лучший вариант для сериализации двоичных данных (8 бит для представления 6, эффективность 75%).

12 голосов
/ 09 марта 2011

Строка для хранения текста, а не двоичных данных.

В кодировке символов по умолчанию для -127 нет символа, поэтому он заменяет его на '?' или 63.

РЕДАКТИРОВАТЬ: Base64 является лучшим вариантом, еще лучше было бы не использовать текст для хранения двоичных данных. Это может быть сделано, но не с любой стандартной кодировкой символов. то есть вы должны сами кодировать.

Чтобы ответить на ваш вопрос буквально, вы можете использовать свою собственную кодировку символов. Это очень плохая идея, так как любой текст может быть закодирован и искажен так же, как вы видели. Использование Base64 позволяет избежать этого, используя символы, которые безопасны в любой кодировке.

byte[] bytes = new byte[256];
for (int i = 0; i < bytes.length; i++)
    bytes[i] = (byte) i;
String text = new String(bytes, 0);
byte[] bytes2 = new byte[text.length()];
for (int i = 0; i < bytes2.length; i++)
    bytes2[i] = (byte) text.charAt(i);
int count = 0;
for (int i = 0; i < bytes2.length; i++)
    if (bytes2[i] != (byte) i)
        System.out.println(i);
    else
        count++;
System.out.println(count + " bytes matched.");
9 голосов
/ 31 декабря 2014

StringOps имеет метод getBytes, я думаю, что это, вероятно, то, что нужно для преобразования строки в массив [байт]

http://www.scala -lang.org / api / 2.10.2/index.html#scala.collection.immutable.StringOps

4 голосов
/ 13 сентября 2016

Используйте правильную кодировку:

scala> (new String(Array[Byte](1, 2, 3, -1, -2, -127), "utf-16")).getBytes("utf-16")
res13: Array[Byte] = Array(-2, -1, 1, 2, 3, -1, -2, -127)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...