ฉันจะเริ่มต้นอาร์เรย์ไบต์ใน Java ได้อย่างไร


138

ฉันต้องเก็บค่าคงที่ (UUIDs) ในรูปแบบอาร์เรย์ไบต์ใน java และฉันสงสัยว่าวิธีที่ดีที่สุดในการเริ่มต้นอาร์เรย์แบบคงที่เหล่านั้นคืออะไร นี่คือสิ่งที่ฉันกำลังทำอยู่ แต่ฉันรู้สึกว่าต้องมีวิธีที่ดีกว่า

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

มีอะไรที่ฉันสามารถใช้ที่อาจมีประสิทธิภาพน้อยกว่า แต่จะดูสะอาดกว่า? ตัวอย่างเช่น:

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

คำตอบ:


111

การใช้ฟังก์ชันแปลงสตริง hexa เป็นbyte[]คุณสามารถทำได้

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

ฉันขอแนะนำให้คุณใช้ฟังก์ชั่นที่กำหนดโดย Dave L ในการแปลงการแสดงสตริงของการถ่ายโอนฐานสิบหกเป็นอาร์เรย์ไบต์โดยใช้ Java?

ฉันใส่ที่นี่เพื่อการอ่านสูงสุด:

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;
}

หากคุณให้ CDRIVES staticและfinalการลดลงของประสิทธิภาพนั้นไม่เกี่ยวข้อง


78
byte[] myvar = "Any String you want".getBytes();

สตริงตัวอักษรสามารถหนีออกมาเพื่อให้ตัวละครใด ๆ :

byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();

50
ไม่ได้เปลี่ยนสตริง"0000"เป็น{0x30,0x30,0x30,0x30}(ASCII) มากกว่า{0x00,0x00,0x00,0x00}(ไบนารี) ตามที่ผู้โพสต์ต้องการหรือไม่
jww

5
ดูที่ชื่อคำถาม จากนั้นดูคำตอบนี้ บอกฉันทีว่ามีอะไรผิดปกติ มันอาจไม่สามารถแก้ปัญหาเฉพาะของผู้โพสต์ได้ ฉันต้องการแปลงสตริงให้เป็นอาร์เรย์ไบต์เพื่อใช้เป็นเมล็ดสำหรับเครื่องกำเนิดตัวเลขเทียมเทียมและนี่ใช้งานได้อย่างมีเสน่ห์
e18r

@ e18r มันสร้างไบต์ใช่ แต่คุณไม่รู้ว่าตั้งแต่นี้ขึ้นอยู่กับชุดอักขระเริ่มต้น อย่างน้อยใช้. getBytes (ต้องการเข้ารหัส)
Quant

@petmez คำถามโง่: ใน JAVA เป็นสิ่งที่ต้องการ "" .getBytes (UTF_8)); (getBytes บนสตริงว่าง) เป็นสิ่งที่ปลอดภัยที่จะทำ? มันถูกกฎหมายหรือไม่ หรือฉันสามารถทำได้: = new byte [0]; ?
Robert Achmann

1
@RobertAchmann "" .getbytes ("UTF-8") ควรคืนอาเรย์ที่ว่างเปล่าและถูกต้องตามกฎหมายอย่างสมบูรณ์
Jazzepi

33

ใน Java 6 มีวิธีการทำสิ่งที่คุณต้องการ:

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

หรือคุณสามารถใช้Google Guava :

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

วิธี Guava มากเกินไปเมื่อคุณใช้อาร์เรย์ขนาดเล็ก แต่ฝรั่งมีรุ่นที่สามารถแยกวิเคราะห์อินพุตสตรีม นี่เป็นฟีเจอร์ที่ดีเมื่อจัดการกับอินพุตเลขฐานสิบหกขนาดใหญ่


ตัวอย่างของ Guava นั้นไม่ค่อยได้ผลเท่าที่ควร - base16().lowerCase().decode(...)ถ้าคุณมีตัวเลขฐานสิบหก docs.guava
Peter DeGlopper

@PeterDeGlopper การค้นหาที่ดีฉันได้อัปเดตคำตอบแล้วตอนนี้โค้ดจะจัดการกับสตริงที่มีอักขระตัวพิมพ์เล็กและใหญ่
stefan.schwetschke

1
javax.xml.bindถูกลบอย่างน่าเศร้าใน Java 9.
randomdude999

7

คุณสามารถใช้คลาส Java UUID เพื่อเก็บค่าเหล่านี้แทนอาร์เรย์ไบต์:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

สร้าง UUID ใหม่โดยใช้ข้อมูลที่ระบุ MostSigBits ใช้สำหรับ 64 บิตที่สำคัญที่สุดของ UUID และ lessSigBits กลายเป็น 64 บิตที่สำคัญที่สุดของ UUID


2

เท่าที่เกี่ยวข้องกับกระบวนการทำความสะอาดคุณสามารถใช้วัตถุByteArrayOutputStream ...

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

// เขียนค่าทั้งหมดไปยัง bObj ทีละรายการโดยใช้

bObj.write(byte value)

// เมื่อเสร็จแล้วคุณจะได้รับ byte [] ใช้

CDRIVES = bObj.toByteArray();

// กว่าที่คุณสามารถทำซ้ำกระบวนการที่คล้ายกันสำหรับ CMYDOCS และ IEFRAME ได้เช่นกัน

หมายเหตุนี่ไม่ใช่วิธีที่มีประสิทธิภาพถ้าคุณมีอาร์เรย์ขนาดเล็กจริงๆ


2

โซลูชันที่ไม่มีไลบรารี, ส่งคืนความยาวแบบไดนามิก, การตีความจำนวนเต็มที่ไม่มีเครื่องหมาย (ไม่ใช่ส่วนเติมเต็มสองรายการ)

    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 };
    }
}

1

ตัวเลือกที่ฉันต้องการในกรณีนี้คือการใช้org.apache.commons.codec.binary.Hexซึ่งมี API ที่มีประโยชน์สำหรับการแปลงระหว่างStringเลขฐานสิบหกและไบนารี ตัวอย่างเช่น:

  1. Hex.decodeHex(char[] data)ซึ่งจะส่ง a DecoderExceptionถ้าไม่มีอักขระที่ไม่ใช่ฐานสิบหกในอาร์เรย์หรือถ้ามีจำนวนอักขระที่เป็นเลขคี่

  2. Hex.encodeHex(byte[] data)char[]เป็นของคู่กันกับวิธีการถอดรหัสข้างต้นและถ่มน้ำลายออก

  3. Hex.encodeHexString(byte[] data)ซึ่งจะแปลงกลับมาจากอาร์เรย์ไปbyteString

การใช้งาน: Hex.decodeHex("dd645a2564cbe648c8336d2be5eafaa6".toCharArray())


1

คุณสามารถใช้ฟังก์ชันยูทิลิตี้นี้:

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

ไม่เหมือนกับตัวแปรของ Denys Séguretและ stefan.schwetschke มันอนุญาตให้แทรกสัญลักษณ์ตัวคั่น (ช่องว่างแท็บ ฯลฯ ) ลงในสตริงอินพุตทำให้อ่านได้ง่ายขึ้น

ตัวอย่างการใช้งาน:

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");

1

ประเภทภายในที่เล็กที่สุดซึ่งเวลารวบรวมสามารถกำหนดโดยเลขฐานสิบหกเป็นอักขระถ่านเช่น

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

เพื่อให้มีอาร์เรย์ไบต์ที่เทียบเท่าหนึ่งอาจปรับใช้การแปลงเป็น

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;
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.