Comment initialiser un tableau d'octets en Java?

138

Je dois stocker des valeurs constantes (UUID) sous forme de tableau d'octets en java, et je me demande quelle serait la meilleure façon d'initialiser ces tableaux statiques. C'est comme ça que je le fais actuellement, mais je pense qu'il doit y avoir une meilleure façon.

private static final byte[] CDRIVES = new byte[] { (byte)0xe0, 0x4f, (byte)0xd0,
    0x20, (byte)0xea, 0x3a, 0x69, 0x10, (byte)0xa2, (byte)0xd8, 0x08, 0x00, 0x2b,
    0x30, 0x30, (byte)0x9d };
private static final byte[] CMYDOCS = new byte[] { (byte)0xba, (byte)0x8a, 0x0d,
    0x45, 0x25, (byte)0xad, (byte)0xd0, 0x11, (byte)0x98, (byte)0xa8, 0x08, 0x00,
    0x36, 0x1b, 0x11, 0x03 };
private static final byte[] IEFRAME = new byte[] { (byte)0x80, 0x53, 0x1c,
    (byte)0x87, (byte)0xa0, 0x42, 0x69, 0x10, (byte)0xa2, (byte)0xea, 0x08,
    0x00, 0x2b, 0x30, 0x30, (byte)0x9d };
...
and so on

Y a-t-il quelque chose que je pourrais utiliser qui serait moins efficace, mais qui aurait l'air plus propre? par exemple:

private static final byte[] CDRIVES =
    new byte[] { "0xe04fd020ea3a6910a2d808002b30309d" };
dfickling
la source

Réponses:

111

En utilisant une fonction convertissant une chaîne hexadécimale en byte[], vous pouvez faire

byte[] CDRIVES = hexStringToByteArray("e04fd020ea3a6910a2d808002b30309d");

Je vous suggère d'utiliser la fonction définie par Dave L dans Convertir une représentation sous forme de chaîne d'un vidage hexadécimal en un tableau d'octets en utilisant Java?

Je l'insère ici pour une lisibilité maximale:

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

Si vous laissez CDRIVES staticet final, la baisse des performances n'est pas pertinente.

Denys Séguret
la source
78
byte[] myvar = "Any String you want".getBytes();

Les littéraux de chaîne peuvent être échappés pour fournir n'importe quel caractère:

byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();
Petmez
la source
50
Cela ne transforme-t-il pas la chaîne "0000"en {0x30,0x30,0x30,0x30}(ASCII) plutôt qu'en {0x00,0x00,0x00,0x00}(binaire) comme le souhaite l'affiche?
jww
5
Regardez le titre de la question. Revenez ensuite à cette réponse. Maintenant dis-moi, qu'est-ce qui ne va pas? Cela ne résoudra peut-être pas le problème particulier de l'affiche, mais cela résoudra le mien. J'avais besoin de transformer une chaîne en un tableau d'octets à utiliser comme graine pour un générateur de nombres pseudo-aléatoires et cela a fonctionné comme un charme.
e18r le
@ e18r Il génère des octets, oui, mais vous ne savez pas lesquels puisque cela dépend du jeu de caractères par défaut. Utilisez au moins .getBytes (souhaitéEncoding).
quant
@petmez question stupide: en JAVA, c'est quelque chose comme "" .getBytes (UTF_8)); (getBytes sur une chaîne vide) une chose sûre à faire? est-ce «légal»? Ou puis-je simplement faire: = new byte [0]; ?
Robert Achmann
1
@RobertAchmann "" .getbytes ("UTF-8") doit renvoyer un tableau vide et est parfaitement légal.
Jazzepi
33

Dans Java 6, il existe une méthode qui fait exactement ce que vous voulez:

private static final byte[] CDRIVES = javax.xml.bind.DatatypeConverter.parseHexBinary("e04fd020ea3a6910a2d808002b30309d")

Vous pouvez également utiliser Google Guava :

import com.google.common.io.BaseEncoding;
private static final byte[] CDRIVES = BaseEncoding.base16().lowerCase().decode("E04FD020ea3a6910a2d808002b30309d".toLowerCase());

La méthode Guava est exagérée, lorsque vous utilisez de petits tableaux. Mais Guava a également des versions qui peuvent analyser les flux d'entrée. C'est une fonctionnalité intéressante lorsqu'il s'agit de grandes entrées hexadécimales.

stefan.schwetschke
la source
L'exemple de Guava ne fonctionne pas tout à fait comme écrit - il doit l'être base16().lowerCase().decode(...)si vous avez des chiffres hexadécimaux minuscules. docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
Peter DeGlopper
@PeterDeGlopper Bonne découverte, j'ai mis à jour la réponse pour que le code gère maintenant les chaînes avec des caractères minuscules et majuscules.
stefan.schwetschke
1
javax.xml.binda été malheureusement supprimé dans Java 9.
randomdude999
7

Vous pouvez utiliser la classe Java UUID pour stocker ces valeurs, au lieu de tableaux d'octets:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

Construit un nouvel UUID à l'aide des données spécifiées. mostSigBits est utilisé pour les 64 bits les plus significatifs de l'UUID et lessSigBits devient les 64 bits les moins significatifs de l'UUID.

Jon
la source
2

En ce qui concerne un processus propre, vous pouvez utiliser l' objet ByteArrayOutputStream ...

ByteArrayOutputStream bObj = new ByteArrayOutputStream();
bObj.reset();

// écrit toutes les valeurs dans bObj une par une en utilisant

bObj.write(byte value)

// une fois terminé, vous pouvez obtenir l'octet [] en utilisant

CDRIVES = bObj.toByteArray();

// que vous pouvez également répéter le processus similaire pour CMYDOCS et IEFRAME,

REMARQUE Ce n'est pas une solution efficace si vous avez vraiment une petite baie.

Amit
la source
2

Une solution sans bibliothèques, longueur dynamique renvoyée, interprétation d'entiers non signés (pas de complément à deux)

    public static byte[] numToBytes(int num){
    if(num == 0){
        return new byte[]{};
    }else if(num < 256){
        return new byte[]{ (byte)(num) };
    }else if(num < 65536){
        return new byte[]{ (byte)(num >>> 8),(byte)num };
    }else if(num < 16777216){
        return new byte[]{ (byte)(num >>> 16),(byte)(num >>> 8),(byte)num };
    }else{ // up to 2,147,483,647
        return new byte[]{ (byte)(num >>> 24),(byte)(num >>> 16),(byte)(num >>> 8),(byte)num };
    }
}
ZMitton
la source
1

Mon option préférée dans ce cas est d'utiliser org.apache.commons.codec.binary.Hexdes API utiles pour la conversion entre Stringy hexadécimal et binaire. Par exemple:

  1. Hex.decodeHex(char[] data)qui jette un DecoderExceptions'il y a des caractères non hexadécimaux dans le tableau, ou s'il y a un nombre impair de caractères.

  2. Hex.encodeHex(byte[] data)est l'équivalent de la méthode de décodage ci-dessus et crache le fichier char[].

  3. Hex.encodeHexString(byte[] data)qui convertit à nouveau d'un bytetableau en un String.

Usage: Hex.decodeHex("dd645a2564cbe648c8336d2be5eafaa6".toCharArray())

rbrtl
la source
1

Vous pouvez utiliser cette fonction utilitaire:

public static byte[] fromHexString(String src) {
    byte[] biBytes = new BigInteger("10" + src.replaceAll("\\s", ""), 16).toByteArray();
    return Arrays.copyOfRange(biBytes, 1, biBytes.length);
}

Contrairement aux variantes de Denys Séguret et stefan.schwetschke, il permet d'insérer des symboles séparateurs (espaces, tabulations, etc.) dans la chaîne d'entrée, ce qui la rend plus lisible.

Exemple d'utilisation:

private static final byte[] CDRIVES
    = fromHexString("e0 4f d0 20 ea 3a 69 10 a2 d8 08 00 2b 30 30 9d");
private static final byte[] CMYDOCS
    = fromHexString("BA8A0D4525ADD01198A80800361B1103");
private static final byte[] IEFRAME
    = fromHexString("80531c87 a0426910 a2ea0800 2b30309d");
John McClane
la source
1

Le plus petit type interne, qui au moment de la compilation peut être attribué par des nombres hexadécimaux est char , comme

private static final char[] CDRIVES_char = new char[] {0xe0, 0xf4, ...};

Afin d'avoir un tableau d'octets équivalent, on peut déployer des conversions comme

public static byte[] charToByteArray(char[] x)
{
    final byte[] res = new byte[x.length];
    for (int i = 0; i < x.length; i++)
    {
        res[i] = (byte) x[i];
    }
    return res;
}

public static byte[][] charToByteArray(char[][] x)
{
    final byte[][] res = new byte[x.length][];
    for (int i = 0; i < x.length; i++)
    {
        res[i] = charToByteArray(x[i]);
    }
    return res;
}
Sam Ginrich
la source
-2
private static final int[] CDRIVES = new int[] {0xe0, 0xf4, ...};

et après l'accès converti en octet.

Frankie
la source