Tableau d'octets à chaîne et retour.. problèmes avec -127
Dans ce qui suit:
scala> (new String(Array[Byte](1, 2, 3, -1, -2, -127))).getBytes
res12: Array[Byte] = Array(1, 2, 3, -1, -2, 63)
Pourquoi -127 est-il converti en 63? et comment puis-je le récupérer comme -127
[EDIT:] version Java ci-dessous (pour montrer que ce n'est pas seulement un "problème 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 réponses
Le constructeur que vous appelez ne rend pas évident que les conversions binaires en chaînes utilisent un décodage: String(byte[] bytes, Charset charset)
. Ce que vous voulez, c'est ne pas utiliser de décodage du tout.
Heureusement, il y a un constructeur pour cela: String(char[] value)
.
Maintenant, vous avez les données dans une chaîne, mais vous voulez les récupérer exactement telles quelles. Mais devinez quoi! getBytes(Charset charset)
c'est vrai, il y a aussi un encodage appliqué automatiquement. Heureusement, il existe une méthode toCharArray()
.
Si vous devez commencer par octets et terminer par octets, vous devez ensuite mapper les tableaux de caractères en octets:
(new String(Array[Byte](1,2,3,-1,-2,-127).map(_.toChar))).toCharArray.map(_.toByte)
Donc, pour résumer: la conversion entre String
et Array[Byte]
implique l'encodage et le décodage. Si vous voulez mettre des données binaires dans une chaîne, vous devez le faire au niveau des personnages. Notez, cependant, que cela vous donnera une chaîne de déchets (c'est-à-dire que le résultat ne sera pas bien formé UTF-16, comme String
devrait l'être), et donc vous feriez mieux de le lire en caractères et de le convertir en octets.
Vous pourriez déplacer le octets en ajoutant, disons, 512; alors vous obtiendriez un tas de points de code Char
uniques valides. Mais cela utilise 16 bits pour représenter tous les 8, une efficacité de codage de 50%. Base64 est une meilleure option pour sérialiser les données binaires (8 bits pour représenter 6, 75% efficace).
La Chaîne sert à stocker du texte et non des données binaires.
Dans votre codage de caractères par défaut il n'y a pas de charcter pour -127 il remplace par"?"ou 63.
EDIT: Base64 est la meilleure option, encore mieux serait de ne pas utiliser de texte pour stocker des données binaires. Cela peut être fait, mais pas avec un codage de caractères standard. c'est-à-dire que vous devez faire l'encodage vous-même.
Pour répondre littéralement à votre question, vous pouvez utiliser votre propre encodage de caractères. C'est une très mauvaise idée comme n'importe quel texte probablement codé et mutilés de la même manière que vous l'avez vu. L'utilisation de Base64 évite cela en utilisant des caractères qui sont sûrs dans n'importe quel encodage.
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.");
StringOps a une méthode getBytes
, Je pense que c'est probablement ce que l'on veut réellement pour convertir String en Array [Byte]
Http://www.scala-lang.org/api/2.10.2/index.html#scala.collection.immutable.StringOps
Utiliser le jeu de caractères:
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)