Chuyển đổi biểu diễn chuỗi của kết xuất hex thành mảng byte bằng Java?


372

Tôi đang tìm cách chuyển đổi một chuỗi dài (từ một bãi chứa), đại diện cho các giá trị hex thành một mảng byte.

Tôi không thể diễn đạt nó tốt hơn người đăng câu hỏi tương tự ở đây .

Nhưng để giữ nguyên bản gốc, tôi sẽ diễn đạt nó theo cách của riêng tôi: giả sử tôi có một chuỗi "00A0BF"mà tôi muốn hiểu là

byte[] {0x00,0xA0,0xBf}

tôi nên làm gì?

Tôi là một người mới làm quen với Java và cuối cùng đã sử dụng BigIntegervà coi chừng các số không hex hàng đầu. Nhưng tôi nghĩ nó thật xấu xí và tôi chắc chắn mình đang thiếu thứ gì đó đơn giản.



Tôi đã thuần hóa BigInteger ở đây .
John McClane

FWIW String.getBytes()sẽ không hoạt động như bạn nghĩ. Phải học cái này một cách khó khăn. if ("FF".getBytes() != "ff".getBytes()) { System.out.println("Try again"); }
tir38

Câu trả lời:


636

Đây là một giải pháp mà tôi nghĩ là tốt hơn bất kỳ bài đăng nào cho đến nay:

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

Lý do tại sao nó là một cải tiến:

  • An toàn với các số 0 đứng đầu (không giống như BigInteger) và với các giá trị byte âm (không giống như Byte.parseByte)

  • Không chuyển đổi Chuỗi thành a char[]hoặc tạo các đối tượng StringBuilder và String cho mỗi byte đơn.

  • Không phụ thuộc thư viện có thể không có sẵn

Vui lòng thêm kiểm tra đối số thông qua asserthoặc ngoại lệ nếu đối số không được biết là an toàn.


2
Bạn có thể đưa ra một ví dụ được giải mã không chính xác, hoặc giải thích nó sai như thế nào không?
Dave L.

5
Nó không hoạt động cho Chuỗi "0". Nó ném một java.lang.StringIndexOutOfBoundException
ovdsrn

49
"0" không phải là đầu vào hợp lệ. Byte yêu cầu hai chữ số thập lục phân mỗi. Như câu trả lời ghi chú, "Hãy thoải mái thêm kiểm tra đối số ... nếu đối số không được biết là an toàn."
Dave L.

12
Javascript không phải là hexString hợp lệ nhưng sẽ trả về -77 bằng cách sử dụng giải pháp như đề xuất).
Trevor Freeman

6
@DaedalusAlpha Tùy thuộc vào ngữ cảnh của bạn, nhưng thông thường tôi thấy tốt hơn là thất bại nhanh và to với những điều như vậy để bạn có thể khắc phục các giả định của mình thay vì âm thầm trả lại dữ liệu không chính xác.
Dave L.

331

Một lớp lót:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Cảnh báo :

  • trong Java 9 Jigsaw, đây không còn là một phần của tập hợp gốc java.se (mặc định), do đó nó sẽ dẫn đến ClassNotFoundException trừ khi bạn chỉ định --add-mô-đun java.se.ee (nhờ @ eckes)
  • Không khả dụng trên Android (nhờ Fabianlưu ý điều đó), nhưng bạn chỉ có thể lấy mã nguồn nếu hệ thống của bạn thiếu javax.xmlvì một số lý do. Cảm ơn @ đã Bert Regelinktrích xuất nguồn.

14
IMHO này nên là chấp nhận / trả lời hàng đầu vì nó ngắn và cleanish (không giống như @ câu trả lời DaveL) và không yêu cầu bất kỳ libs bên ngoài (như câu trả lời của skaffman). Ngoài ra, <Nhập một trò đùa đã mòn về việc phát minh lại xe đạp> .
Priidu Neemre

9
ví dụ, lớp datatypeconverter không có sẵn trong Android.
Fabian

4
Cảnh báo: trong Java 9 Jigsaw, đây không còn là một phần của java.setập hợp gốc (mặc định), do đó, nó sẽ dẫn đến một kết quả ClassNotFoundExceptiontrừ khi bạn chỉ định--add-modules java.se.ee
vào

2
@dantebarba Tôi nghĩ javax.xml.bind.DatatypeConverterđã cung cấp một phương pháp để mã hóa / giải mã dữ liệu Base64. Xem parseBase64Binary()printBase64Binary().
DragShot

2
Để thêm vào các vấn đề với DataTypeConverter, Java SE 11 đã loại bỏ hoàn toàn API JAXB và hiện chỉ được bao gồm trong Java EE. Bạn cũng có thể thêm nó dưới dạng phụ thuộc Maven, như được đề xuất tại đây: stackoverflow.com/a/43574427/7347751
David Mordigal

79

Lớp Hex trong commons-codec sẽ làm điều đó cho bạn.

http://commons.apache.org/codec/

import org.apache.commons.codec.binary.Hex;
...
byte[] decoded = Hex.decodeHex("00A0BF");
// 0x00 0xA0 0xBF

6
Điều này cũng có vẻ tốt. Xem org.apache.commons.codec.binary.Hex.decodeHex ()
Dave L.

Nó rất thú vị. Nhưng tôi thấy giải pháp của họ khó theo dõi. Nó có bất kỳ lợi thế nào so với những gì bạn đề xuất (ngoài việc kiểm tra số chars chẵn) không?
rafraf

38

Bây giờ bạn có thể sử dụng BaseEncoding trong guavađể thực hiện điều này.

BaseEncoding.base16().decode(string);

Để đảo ngược nó sử dụng

BaseEncoding.base16().encode(bytes);

27

Trên thực tế, tôi nghĩ rằng BigInteger là giải pháp rất hay:

new BigInteger("00A0BF", 16).toByteArray();

Chỉnh sửa: Không an toàn cho số không hàng đầu , như ghi chú của người đăng.


Tôi cũng nghĩ như vậy ban đầu. Và cảm ơn bạn đã ghi lại nó - Tôi chỉ nghĩ rằng tôi nên ... nó đã làm một số điều kỳ lạ mặc dù tôi không thực sự hiểu - như bỏ qua một số 0x00 hàng đầu và cũng trộn lẫn thứ tự 1 byte trong chuỗi 156 byte tôi đã chơi với.
rafraf

2
Đó là một điểm tốt về việc dẫn đầu 0. Tôi không chắc chắn rằng tôi tin rằng nó có thể trộn lẫn thứ tự byte và sẽ rất thích thú khi thấy nó được trình diễn.
Dave L.

1
vâng, ngay khi tôi nói, tôi cũng không tin tôi :) Tôi đã chạy so sánh mảng byte từ BigInteger với mmyer'fromHexString và (không có 0x00) so với chuỗi vi phạm - chúng giống hệt nhau. Việc "trộn lẫn" đã xảy ra, nhưng nó có thể là một cái gì đó khác. Tôi sẽ xem xét kỹ hơn vào ngày mai
rafraf

3
Vấn đề với BigInteger là phải có "dấu bit". Nếu byte hàng đầu có tập bit cao thì mảng byte kết quả có thêm 0 ở vị trí số 1. Nhưng vẫn là +1.
Xám

25

Một lớp lót:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Đối với những người bạn quan tâm đến mã thực tế đằng sau One-liners từ FractalizeR (Tôi cần điều đó vì javax.xml.bind không có sẵn cho Android (theo mặc định)), điều này đến từ com.sun.xml.i INTERNal.bind. DatatypeConverterImpl.java :

public byte[] parseHexBinary(String s) {
    final int len = s.length();

    // "111" is not a valid hex encoding.
    if( len%2 != 0 )
        throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);

    byte[] out = new byte[len/2];

    for( int i=0; i<len; i+=2 ) {
        int h = hexToBin(s.charAt(i  ));
        int l = hexToBin(s.charAt(i+1));
        if( h==-1 || l==-1 )
            throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);

        out[i/2] = (byte)(h*16+l);
    }

    return out;
}

private static int hexToBin( char ch ) {
    if( '0'<=ch && ch<='9' )    return ch-'0';
    if( 'A'<=ch && ch<='F' )    return ch-'A'+10;
    if( 'a'<=ch && ch<='f' )    return ch-'a'+10;
    return -1;
}

private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length*2);
    for ( byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}

3
DatatypeConverter cũng không có sẵn trong Java 9 theo mặc định. Điều nguy hiểm là mã sử dụng nó sẽ biên dịch theo Java 1.8 trở về trước (Java 9 với các cài đặt nguồn thành trước đó), nhưng có một ngoại lệ thời gian chạy trong Java 9 mà không có "--add-mô-đun java.se.ee".
Stephen M -on đình công-

24

Các HexBinaryAdaptercung cấp khả năng sắp xếp và unmarshal giữa Stringbyte[].

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public byte[] hexToBytes(String hexString) {
     HexBinaryAdapter adapter = new HexBinaryAdapter();
     byte[] bytes = adapter.unmarshal(hexString);
     return bytes;
}

Đó chỉ là một ví dụ tôi đã nhập vào ... Tôi thực sự chỉ sử dụng nó và không cần phải tạo một phương pháp riêng để sử dụng nó.


5
Nó chỉ hoạt động nếu chuỗi đầu vào (hexString) có số ký tự chẵn. Mặt khác: Ngoại lệ trong luồng "chính" java.lang.IllegalArgumentException: hexBinary cần có độ dài bằng nhau:
ovdsrn

3
Oh, cảm ơn đã chỉ ra rằng. Một người dùng thực sự không nên có số lượng ký tự lẻ vì mảng byte được biểu diễn dưới dạng {0x00,0xA0,0xBf}. Mỗi byte có hai chữ số hex hoặc nibble. Vì vậy, bất kỳ số byte nào cũng phải luôn có số lượng ký tự chẵn. Cảm ơn đã đề cập đến điều này.
GrkEngineer

8
Bạn có thể sử dụng trực tiếp java.xml.bind.DatatypeConverter.parseHexBinary (hexString) thay vì sử dụng HexBinaryAd CHƯƠNG (lần lượt gọi DatatypeConverter). Bằng cách này, bạn không phải tạo một đối tượng bộ điều hợp (vì các phương thức DatatypeConverter là tĩnh).
Trevor Freeman

javax.xml.bind. * không còn khả dụng trong Java 9. Điều nguy hiểm là mã sử dụng nó sẽ biên dịch theo Java 1.8 trở về trước (Java 9 với các cài đặt nguồn thành trước đó), nhưng có một ngoại lệ thời gian chạy chạy trong Java 9.
Stephen M -on đình công-

15

Đây là một phương pháp thực sự hoạt động (dựa trên một số câu trả lời bán đúng trước đó):

private static byte[] fromHexString(final String encoded) {
    if ((encoded.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[encoded.length()/2];
    final char enc[] = encoded.toCharArray();
    for (int i = 0; i < enc.length; i += 2) {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[i]).append(enc[i + 1]);
        result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

Vấn đề duy nhất có thể mà tôi có thể thấy là nếu chuỗi đầu vào quá dài; gọi toCharArray () tạo một bản sao của mảng bên trong của chuỗi.

EDIT: Ồ, và nhân tiện, các byte được ký bằng Java, vì vậy chuỗi đầu vào của bạn chuyển đổi thành [0, -96, -65] thay vì [0, 160, 191]. Nhưng có lẽ bạn đã biết điều đó rồi.


1
Cảm ơn Michael - bạn là một người cứu rỗi cuộc sống! Làm việc trên một dự án BlackBerry và cố gắng chuyển đổi một chuỗi đại diện của một byte trở lại byte ... bằng cách sử dụng phương thức "Byte.parseByte (byteString, 16)" của RIM. Giữ một NumberFormatExcpetion. Đã dành hàng giờ để đánh dấu tại sao. Đề xuất của bạn về "Integer.praseInt ()" đã thực hiện thủ thuật này. Cảm ơn một lần nữa !!
BonanzaDriver

12

Trong Android, nếu bạn đang làm việc với hex, bạn có thể thử okio .

cách sử dụng đơn giản:

byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();

và kết quả sẽ là

[-64, 0, 6, 0, 0]

Tôi đã thử nghiệm nhiều phương pháp khác nhau nhưng phương pháp này nhanh nhất ít nhất gấp đôi!
poby

5

Các BigInteger()phương pháp từ java.math là rất chậm và không recommandable.

Integer.parseInt(HEXString, 16)

có thể gây ra sự cố với một số ký tự mà không chuyển đổi sang Digit / Integer

một phương pháp làm việc tốt:

Integer.decode("0xXX") .byteValue()

Chức năng:

public static byte[] HexStringToByteArray(String s) {
    byte data[] = new byte[s.length()/2];
    for(int i=0;i < s.length();i+=2) {
        data[i/2] = (Integer.decode("0x"+s.charAt(i)+s.charAt(i+1))).byteValue();
    }
    return data;
}

Chúc bạn vui vẻ


4

EDIT: như được chỉ ra bởi @mmyer, phương pháp này không hoạt động trên đầu vào có chứa các chuỗi con tương ứng với các byte có tập bit cao ("80" - "FF"). Lời giải thích có tại Bug ID: 6259307 Byte.parseByte không hoạt động như quảng cáo trong Tài liệu SDK .

public static final byte[] fromHexString(final String s) {
    byte[] arr = new byte[s.length()/2];
    for ( int start = 0; start < s.length(); start += 2 )
    {
        String thisByte = s.substring(start, start+2);
        arr[start/2] = Byte.parseByte(thisByte, 16);
    }
    return arr;
}

1
Đóng, nhưng phương thức này không thành công trên đầu vào đã cho "00A0BBF". Xem bug.sun.com/ormsdatabase/view_orms.do?orms_id=6259307 .
Michael Myers

1
Điều kỳ lạ là nó không đối phó với "9C"
rafraf

1
@mmyer: whoa. Điều đó không tốt. Xin lỗi vì sự nhầm lẫn. @ravigad: 9C có cùng một vấn đề vì trong trường hợp này, bit cao được đặt.
Blair Conrad

(byte) Short.parseShort (thisByte, 16) giải quyết vấn đề đó
Jamey Hicks

3

Để biết giá trị của nó, đây là một phiên bản khác hỗ trợ các chuỗi có độ dài lẻ, mà không cần dùng đến nối chuỗi.

public static byte[] hexStringToByteArray(String input) {
    int len = input.length();

    if (len == 0) {
        return new byte[] {};
    }

    byte[] data;
    int startIdx;
    if (len % 2 != 0) {
        data = new byte[(len / 2) + 1];
        data[0] = (byte) Character.digit(input.charAt(0), 16);
        startIdx = 1;
    } else {
        data = new byte[len / 2];
        startIdx = 0;
    }

    for (int i = startIdx; i < len; i += 2) {
        data[(i + 1) / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4)
                + Character.digit(input.charAt(i+1), 16));
    }
    return data;
}

2

Tôi đã luôn sử dụng một phương pháp như

public static final byte[] fromHexString(final String s) {
    String[] v = s.split(" ");
    byte[] arr = new byte[v.length];
    int i = 0;
    for(String val: v) {
        arr[i++] =  Integer.decode("0x" + val).byteValue();

    }
    return arr;
}

phương thức này phân tách trên các giá trị hex được phân tách bằng dấu cách nhưng sẽ không khó để làm cho nó phân tách chuỗi theo bất kỳ tiêu chí nào khác, chẳng hạn như thành các nhóm gồm hai ký tự.


Việc nối chuỗi là không cần thiết. Chỉ cần sử dụng Integer.valueOf (val, 16).
Michael Myers

Tôi đã thử sử dụng các chuyển đổi cơ số như thế trước đây và tôi đã có kết quả hỗn hợp
pfranza

cảm ơn - thật kỳ lạ, nó hoạt động tốt với chuỗi này: "9C001C" hoặc "001C21" và thất bại với chuỗi này: "9C001C21" Ngoại lệ trong luồng "chính" java.lang.NumberFormatException: Đối với chuỗi đầu vào: "9C001C21" tại java.lang. NumberFormatException.forInputString (Nguồn không xác định)
rafraf

(Đó là không lẻ hơn trong Byte/ bytetrường hợp: set bit cao nhất mà không hàng đầu -)
lọ

2

Tôi thích giải pháp Character.digit, nhưng đây là cách tôi giải quyết nó

public byte[] hex2ByteArray( String hexString ) {
    String hexVal = "0123456789ABCDEF";
    byte[] out = new byte[hexString.length() / 2];

    int n = hexString.length();

    for( int i = 0; i < n; i += 2 ) {
        //make a bit representation in an int of the hex value 
        int hn = hexVal.indexOf( hexString.charAt( i ) );
        int ln = hexVal.indexOf( hexString.charAt( i + 1 ) );

        //now just shift the high order nibble and add them together
        out[i/2] = (byte)( ( hn << 4 ) | ln );
    }

    return out;
}

2

Bộ luật được trình bày bởi Bert Regelink đơn giản là không hoạt động. Hãy thử như sau:

import javax.xml.bind.DatatypeConverter;
import java.io.*;

public class Test
{  
    @Test
    public void testObjectStreams( ) throws IOException, ClassNotFoundException
    {     
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);

            String stringTest = "TEST";
            oos.writeObject( stringTest );

            oos.close();
            baos.close();

            byte[] bytes = baos.toByteArray();
            String hexString = DatatypeConverter.printHexBinary( bytes);
            byte[] reconvertedBytes = DatatypeConverter.parseHexBinary(hexString);

            assertArrayEquals( bytes, reconvertedBytes );

            ByteArrayInputStream bais = new ByteArrayInputStream(reconvertedBytes);
            ObjectInputStream ois = new ObjectInputStream(bais);

            String readString = (String) ois.readObject();

            assertEquals( stringTest, readString);
        }
    }

2
Đây thực sự là một vấn đề khác, và có lẽ thuộc về một chủ đề khác.
Sean Coffey

1

Tôi thấy Kernel Panic có giải pháp hữu ích nhất đối với tôi, nhưng gặp vấn đề nếu chuỗi hex là một số lẻ. giải quyết nó theo cách này:

boolean isOdd(int value)
{
    return (value & 0x01) !=0;
}

private int hexToByte(byte[] out, int value)
{
    String hexVal = "0123456789ABCDEF"; 
    String hexValL = "0123456789abcdef";
    String st = Integer.toHexString(value);
    int len = st.length();
    if (isOdd(len))
        {
        len+=1; // need length to be an even number.
        st = ("0" + st);  // make it an even number of chars
        }
    out[0]=(byte)(len/2);
    for (int i =0;i<len;i+=2)
    {
        int hh = hexVal.indexOf(st.charAt(i));
            if (hh == -1)  hh = hexValL.indexOf(st.charAt(i));
        int lh = hexVal.indexOf(st.charAt(i+1));
            if (lh == -1)  lh = hexValL.indexOf(st.charAt(i+1));
        out[(i/2)+1] = (byte)((hh << 4)|lh);
    }
    return (len/2)+1;
}

Tôi đang thêm một số số hex vào một mảng, vì vậy tôi chuyển tham chiếu đến mảng tôi đang sử dụng và int tôi cần chuyển đổi và trả về vị trí tương đối của số hex tiếp theo. Vì vậy, mảng byte cuối cùng có [0] số cặp hex, [1 ...] cặp hex, sau đó là số cặp ...


1

Dựa trên giải pháp được bình chọn của op, những điều sau đây sẽ hiệu quả hơn một chút:

  public static byte [] hexStringToByteArray (final String s) {
    if (s == null || (s.length () % 2) == 1)
      throw new IllegalArgumentException ();
    final char [] chars = s.toCharArray ();
    final int len = chars.length;
    final byte [] data = new byte [len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
    }
    return data;
  }

Bởi vì: chuyển đổi ban đầu thành một mảng char cho phép kiểm tra độ dài trong charAt


1

Nếu bạn có một ưu tiên cho các luồng Java 8 như kiểu mã hóa của mình thì điều này có thể đạt được bằng cách sử dụng chỉ các nguyên hàm JDK.

String hex = "0001027f80fdfeff";

byte[] converted = IntStream.range(0, hex.length() / 2)
    .map(i -> Character.digit(hex.charAt(i * 2), 16) << 4 | Character.digit(hex.charAt((i * 2) + 1), 16))
    .collect(ByteArrayOutputStream::new,
             ByteArrayOutputStream::write,
             (s1, s2) -> s1.write(s2.toByteArray(), 0, s2.size()))
    .toByteArray();

Các , 0, s2.size()tham số trong hàm concatenate collector có thể được bỏ qua nếu bạn không nhớ IOException.


0
public static byte[] hex2ba(String sHex) throws Hex2baException {
    if (1==sHex.length()%2) {
        throw(new Hex2baException("Hex string need even number of chars"));
    }

    byte[] ba = new byte[sHex.length()/2];
    for (int i=0;i<sHex.length()/2;i++) {
        ba[i] = (Integer.decode(
                "0x"+sHex.substring(i*2, (i+1)*2))).byteValue();
    }
    return ba;
}

0

Giải pháp chính thức của tôi:

/**
 * Decodes a hexadecimally encoded binary string.
 * <p>
 * Note that this function does <em>NOT</em> convert a hexadecimal number to a
 * binary number.
 *
 * @param hex Hexadecimal representation of data.
 * @return The byte[] representation of the given data.
 * @throws NumberFormatException If the hexadecimal input string is of odd
 * length or invalid hexadecimal string.
 */
public static byte[] hex2bin(String hex) throws NumberFormatException {
    if (hex.length() % 2 > 0) {
        throw new NumberFormatException("Hexadecimal input string must have an even length.");
    }
    byte[] r = new byte[hex.length() / 2];
    for (int i = hex.length(); i > 0;) {
        r[i / 2 - 1] = (byte) (digit(hex.charAt(--i)) | (digit(hex.charAt(--i)) << 4));
    }
    return r;
}

private static int digit(char ch) {
    int r = Character.digit(ch, 16);
    if (r < 0) {
        throw new NumberFormatException("Invalid hexadecimal string: " + ch);
    }
    return r;
}

Giống như Hàm hex2bin () của PHP nhưng theo kiểu Java.

Thí dụ:

String data = new String(hex2bin("6578616d706c65206865782064617461"));
// data value: "example hex data"

0

Đến bữa tiệc muộn, nhưng tôi đã hợp nhất câu trả lời ở trên của DaveL vào một lớp học với hành động ngược lại - chỉ trong trường hợp nó có ích.

public final class HexString {
    private static final char[] digits = "0123456789ABCDEF".toCharArray();

    private HexString() {}

    public static final String fromBytes(final byte[] bytes) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            buf.append(HexString.digits[(bytes[i] >> 4) & 0x0f]);
            buf.append(HexString.digits[bytes[i] & 0x0f]);
        }
        return buf.toString();
    }

    public static final byte[] toByteArray(final String hexString) {
        if ((hexString.length() % 2) != 0) {
            throw new IllegalArgumentException("Input string must contain an even number of characters");
        }
        final int len = hexString.length();
        final byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }
}

Và lớp kiểm tra JUnit:

public class TestHexString {

    @Test
    public void test() {
        String[] tests = {"0FA1056D73", "", "00", "0123456789ABCDEF", "FFFFFFFF"};

        for (int i = 0; i < tests.length; i++) {
            String in = tests[i];
            byte[] bytes = HexString.toByteArray(in);
            String out = HexString.fromBytes(bytes);
            System.out.println(in); //DEBUG
            System.out.println(out); //DEBUG
            Assert.assertEquals(in, out);

        }

    }

}

0

Tôi biết đây là một chủ đề rất cũ, nhưng vẫn muốn thêm giá trị đồng xu của tôi.

Nếu tôi thực sự cần mã hóa một chuỗi hex đơn giản thành trình chuyển đổi nhị phân, tôi muốn làm như sau.

public static byte[] hexToBinary(String s){

  /*
   * skipped any input validation code
   */

  byte[] data = new byte[s.length()/2];

  for( int i=0, j=0; 
       i<s.length() && j<data.length; 
       i+=2, j++)
  {
     data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
  }

  return data;
}

0

Cho đến nay không phải là giải pháp sạch nhất. Nhưng nó hoạt động với tôi và được định dạng tốt:

private String createHexDump(byte[] msg, String description) {
    System.out.println();
    String result = "\n" + description;
    int currentIndex = 0;
    int printedIndex = 0;
    for(int i=0 ; i<msg.length ; i++){
        currentIndex++;
        if(i == 0){
            result += String.format("\n  %04x ", i);
        }
        if(i % 16 == 0 && i != 0){
            result += " | ";
            for(int j=(i-16) ; j<msg.length && j<i ; j++) {
                char characterToAdd = (char) msg[j];
                if (characterToAdd == '\n') {
                    characterToAdd = ' ';
                }
                result += characterToAdd;
                printedIndex++;
            }

            result += String.format("\n  %04x ", i);
        }

        result += String.format("%02x ", msg[i]);
    }

    if(currentIndex - printedIndex > 0){
        int leftOvers = currentIndex - printedIndex;
        for(int i=0 ; i<16-leftOvers ; i++){
            result += "   ";
        }

        result += " | ";

        for(int i=msg.length-leftOvers ; i<msg.length ; i++){
            char characterToAdd = (char) msg[i];
            if (characterToAdd == '\n') {
                characterToAdd = ' ';
            }
            result += characterToAdd;
        }
    }

    result += "\n";

    return result;
}

Đầu ra:

  S -> C
    0000 0b 00 2e 06 4d 6f 72 69 74 7a 53 6f 6d 65 20 54  |  .Heyyy Some T
    0010 43 50 20 73 74 75 66 66 20 49 20 63 61 70 74 75  | CP stuff I captu
    0020 72 65 64 2e 2e 77 65 6c 6c 20 66 6f 72 6d 61 74  | red..well format
    0030 3f                                               | ?

-2

Tôi nghĩ sẽ làm điều đó cho bạn. Tôi đã ghép nó lại với nhau từ một hàm tương tự trả về dữ liệu dưới dạng chuỗi:

private static byte[] decode(String encoded) {
    byte result[] = new byte[encoded/2];
    char enc[] = encoded.toUpperCase().toCharArray();
    StringBuffer curr;
    for (int i = 0; i < enc.length; i += 2) {
        curr = new StringBuffer("");
        curr.append(String.valueOf(enc[i]));
        curr.append(String.valueOf(enc[i + 1]));
        result[i] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

Trước tiên, bạn không cần phải chuyển đổi chuỗi thành chữ hoa. Thứ hai, có thể nối các ký tự trực tiếp vào StringBuffer, sẽ hiệu quả hơn nhiều.
Michael Myers

-2

Đối với tôi đây là giải pháp, HEX = "FF01" sau đó chia thành FF (255) và 01 (01)

private static byte[] BytesEncode(String encoded) {
    //System.out.println(encoded.length());
    byte result[] = new byte[encoded.length() / 2];
    char enc[] = encoded.toUpperCase().toCharArray();
    String curr = "";
    for (int i = 0; i < encoded.length(); i=i+2) {
        curr = encoded.substring(i,i+2);
        System.out.println(curr);
        if(i==0){
            result[i]=((byte) Integer.parseInt(curr, 16));
        }else{
            result[i/2]=((byte) Integer.parseInt(curr, 16));
        }

    }
    return result;
}

Câu hỏi này đã được trả lời trong một thời gian và có một số lựa chọn thay thế tốt; thật không may, câu trả lời của bạn không cung cấp bất kỳ giá trị được cải thiện đáng kể tại thời điểm này.
rfornal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.