Làm cách nào để chuyển đổi một mảng byte thành chuỗi hex trong Java?


649

Tôi có một mảng byte chứa đầy các số hex và in nó một cách dễ dàng là khá vô nghĩa vì có nhiều yếu tố không thể in được. Những gì tôi cần là hexcode chính xác ở dạng:3a5f771c


12
Tại sao không thử trước và cho chúng tôi thấy những gì bạn đã có. Bạn không có gì để mất và tất cả để đạt được. Integer có một toHexString(...)phương pháp có thể giúp ích nếu đây là những gì bạn đang tìm kiếm. Cũng String.format(...)có thể thực hiện một số thủ thuật định dạng gọn gàng bằng cách sử dụng %2xchuỗi mã.
Hovercraft Full Of Eels


"Điều tôi cần là hexcode chính xác ở dạng: 3a5f771c ..." - bạn đã yêu cầu một biểu mẫu chính xác, nhưng bạn không cung cấp một ví dụ chính xác. Tiếp tục với những gì bạn cung cấp, chuyển đổi bốn byte đầu tiên thành một chuỗi, sau đó nối các hình elip thành chuỗi.
jww

1
Với sự trợ giúp của luồng trong Java 8, nó có thể được triển khai đơn giản như: Chuỗi tĩnh byteArrayToHex (byte [] a) {return IntStream.range (0, a.length) .mapToObj (i -> String.format ("% 02x ", a [i])) .reduce ((acc, v) -> acc +" "+ v) .get (); }
tibetty

Câu trả lời:


901

Từ các cuộc thảo luận ở đây , và đặc biệt này câu trả lời, đây là chức năng Tôi hiện đang sử dụng:

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Điểm chuẩn nhỏ bé của riêng tôi (một triệu byte một nghìn lần, 256 byte 10 triệu lần) cho thấy nó nhanh hơn nhiều so với bất kỳ thay thế nào khác, khoảng một nửa thời gian trên các mảng dài. So với câu trả lời tôi đã lấy nó, chuyển sang ops bitwise --- như được đề xuất trong cuộc thảo luận --- cắt giảm khoảng 20% ​​thời gian cho các mảng dài. (Chỉnh sửa: Khi tôi nói nó nhanh hơn các lựa chọn thay thế, ý tôi là mã thay thế được cung cấp trong các cuộc thảo luận. Hiệu suất tương đương với Commons Codec, sử dụng mã rất giống nhau.)

Phiên bản 2k20, liên quan đến chuỗi nhỏ gọn Java 9:

private static final byte[] HEX_ARRAY = "0123456789ABCDEF".toByteArray();
public static String bytesToHex(byte[] bytes) {
    byte[] hexChars = new byte[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars, StandardCharsets.UTF_8);
}

266
Tôi vừa tìm thấy javax.xml.bind.DataTypeConverter , một phần của bản phân phối chuẩn. Tại sao điều này không xuất hiện khi bạn Google loại vấn đề này? Rất nhiều công cụ hữu ích, bao gồm String printHexBinary(byte[])byte[] parseHexBinary(String). printHexBinarytuy nhiên, chậm hơn nhiều so với hàm trong câu trả lời này. (Tôi đã kiểm tra nguồn; nó sử dụng một stringBuilder. parseHexBinarySử dụng một mảng.) Thực sự, mặc dù, đối với hầu hết các mục đích, nó đủ nhanh và bạn có thể đã có nó.
lẽ WeCouldStealAVan

75
+1 cho câu trả lời vì Android không có DataTypeConverter
Vaiden

7
@maybeweCouldStealAVan: JDK 7 hiện là nguồn mở. Chúng ta nên gửi một bản vá để cải thiện hiệu suất cho printHexBinary?
kevinarpe

3
@maybeweCouldStealAVan bạn có thể vui lòng giải thích cách thức hoạt động của nó. Tôi theo dõi phần lớn nhưng thực sự thích hiểu những gì đang xảy ra khi sử dụng mã. Cảm ơn!
jjNford

24
javax.xml.bind.DataTypeConverterđang bị xóa khỏi Java 11.
The Impaler

421

Thư viện Codec Apache Commons có một lớp Hex để thực hiện loại công việc này.

import org.apache.commons.codec.binary.Hex;

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );

12
@cytinus - Downvote của tôi đã xảy ra 4 tháng trước vì vậy tôi không hoàn toàn chắc chắn những gì tôi đang nghĩ, nhưng tôi có lẽ đang phản đối kích thước của thư viện. Đây là một chức năng nhỏ trong chương trình; không cần thêm một thư viện cồng kềnh như vậy vào dự án để thực hiện nó.
ArtOfWarfare 30/03/13

6
@ArtOfWarefare Tôi đồng ý, vì vậy thay vì import org.apache.commons.codec.*;bạn có thể làmimport org.apache.commons.codec.binary.Hex;
cytinus

12
@ArtOfWarfare Tôi phải không đồng ý. Điều khủng khiếp duy nhất là các thư viện commache commons không được bao gồm theo mặc định với JRE và JDK. Có một số thư viện rất hữu ích, chúng thực sự nên có trên đường dẫn lớp của bạn theo mặc định, và đây là một trong số chúng.
corsiKa

29
Tôi rất khuyến khích câu trả lời này được hoán đổi là câu trả lời hàng đầu. Luôn bỏ phiếu để sử dụng thư viện mã nguồn mở, được kiểm tra tốt về mã tùy chỉnh không cải thiện về nó.
Dmitriy Likhten

6
Hoặc trong trường hợp bạn sử dụng BouncyCastle ( org.bouncycastle: bcprov-jdk15on ), bạn có thể sử dụng lớp này : org.bouncycastle.util.encoders.Hex, với phương pháp này:String toHexString(byte[] data)
Guillaume Husta 30/03/2017

320

Phương thức javax.xml.bind.DatatypeConverter.printHexBinary(), một phần của Kiến trúc Java cho liên kết XML (JAXB) , là một cách thuận tiện để chuyển đổi một byte[]chuỗi hex. Các DatatypeConverterlớp học cũng bao gồm nhiều phương pháp dữ liệu thao tác hữu ích khác.

Trong Java 8 trở về trước, JAXB là một phần của thư viện chuẩn Java. Nó không được chấp nhận với Java 9 và bị xóa bằng Java 11 , như một phần trong nỗ lực chuyển tất cả các gói Java EE vào các thư viện của riêng họ. Đó là một câu chuyện dài . Bây giờ, javax.xml.bindkhông tồn tại và nếu bạn muốn sử dụng JAXB, có chứa DatatypeConverter, bạn sẽ cần cài đặt API JAXBJAXB Runtime từ Maven.

Ví dụ sử dụng:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

Sẽ cho kết quả:

000086003D

Câu trả lời này giống như câu trả lời này .


13
Một giải pháp tốt, mặc dù đáng buồn là không phải là một giải pháp hợp lệ trong Android.
Kazriko

@Kazriko có thể bạn muốn đọc code.google.com/p/dalvik/wiki/JavaxPackages . Đây là một cách để đưa các lớp javax vào Android. Nhưng nếu bạn chỉ muốn chuyển đổi sang hex, nó không đáng để gặp rắc rối.
PhoneixS

13
DatatypeConverter không còn truy cập được kể từ JDK 9
pmcollins

3
@PhoneixS Nó vẫn ở đó, nhưng không phải là một phần của thời gian chạy mặc định (do các mô-đun Java 9).
Tiêu điểm

2
không dựa vào javax.xml.bind, nó biên dịch tốt nhưng không thể tìm thấy trong thời gian chạy. nếu bạn làm như vậy, hãy chuẩn bị để xử lý java.lang.NoClassDefFoundError
Dmitry

227

Giải pháp đơn giản nhất, không có lib bên ngoài, không có hằng số:

public static String byteArrayToHex(byte[] a) {
   StringBuilder sb = new StringBuilder(a.length * 2);
   for(byte b: a)
      sb.append(String.format("%02x", b));
   return sb.toString();
}

14
Điều này rất chậm, trung bình chậm hơn 1000 lần (cho 162 byte) so với tốc độ cao nhất. Tránh sử dụng String.Format nếu hiệu suất có vấn đề.
pt123

8
Có lẽ chậm. Nó tốt cho những điều xảy ra đôi khi, chẳng hạn như đăng nhập hoặc tương tự.
Con trỏ Null

29
Nếu nó chậm, vậy thì sao? Trong trường hợp sử dụng của tôi, nó chỉ dành cho một câu lệnh gỡ lỗi, vì vậy cảm ơn vì đoạn mã này.
vikingsteve 18/11/13

8
Việc sử dụng lại thư viện bằng cách bao gồm một tệp JAR bổ sung vài chục kB sẽ không thực sự hiệu quả nếu tất cả những gì bạn cần là chức năng này (trên một số nền tảng như Android, toàn bộ Jar được đưa vào ứng dụng cuối). Và đôi khi mã ngắn hơn và rõ ràng hơn sẽ tốt hơn khi không cần hiệu năng.
personne3000

2
@ personne3000 có thể, nhưng trong trường hợp đó bạn cần hỗ trợ truyền phát, không phải là một tính năng gọi đơn. Điều này là dễ hiểu và ghi nhớ, và do đó để duy trì.
Maarten Bodewes

59

Một giải pháp ổi, cho đầy đủ:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

Bây giờ hex"48656c6c6f20776f726c64".


Trong ổi bạn cũng có thể sử dụng new HashCode(bytes).toString().
mfulton26

1
Kể từ Guava 22.0, đó làHashCode.fromBytes(checksum).toString()
Devstr

43

Công cụ oneliner đơn giản này hoạt động với tôi
String result = new BigInteger(1, inputBytes).toString(16);
EDIT - Sử dụng điều này sẽ loại bỏ các số không hàng đầu, nhưng hey đã làm việc cho trường hợp sử dụng của tôi. Cảm ơn @Voicu đã chỉ ra


56
Oneliner này giảm byte hàng đầu.
Voicu

@Voicu ... Và nó sẽ thêm 50% hàng đầu thời gian.
Maarten Bodewes

27

Dưới đây là một số tùy chọn phổ biến được sắp xếp từ đơn giản (một lớp) đến phức tạp (thư viện khổng lồ). Nếu bạn quan tâm đến hiệu suất, hãy xem các điểm chuẩn vi mô dưới đây.

Tùy chọn 1: Đoạn mã - Đơn giản

Một giải pháp rất đơn giản là sử dụng BigIntegerbiểu diễn hex của:

new BigInteger(1, someByteArray).toString(16)

Lưu ý rằng vì điều này xử lý các số không phải là chuỗi byte tùy ý , nó sẽ bỏ qua các số 0 đứng đầu - điều này có thể hoặc không thể là những gì bạn muốn (ví dụ 000AE3so 0AE3với đầu vào 3 byte). Điều này cũng rất chậm, chậm hơn khoảng 100 lần so với tùy chọn tiếp theo.

Tùy chọn 2: Đoạn mã - Nâng cao

Dưới đây là một đoạn mã đầy đủ, sao chép và có thể dán được hỗ trợ chữ hoa / chữ thườngchữ cuối . Nó được tối ưu hóa để giảm thiểu độ phức tạp của bộ nhớ và tối đa hóa hiệu suất và phải tương thích với tất cả các phiên bản Java hiện đại (5+).

private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};

public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {

    // our output size will be exactly 2x byte-array length
    final char[] buffer = new char[byteArray.length * 2];

    // choose lower or uppercase lookup table
    final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;

    int index;
    for (int i = 0; i < byteArray.length; i++) {
        // for little endian we count from last to first
        index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;

        // extract the upper 4 bit and look up char (0-A)
        buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
        // extract the lower 4 bit and look up char (0-A)
        buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
    }
    return new String(buffer);
}

public static String encode(byte[] byteArray) {
    return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}

Mã nguồn đầy đủ với giấy phép và bộ giải mã Apache v2 có thể được tìm thấy ở đây .

Tùy chọn 3: Sử dụng một thư viện tối ưu hóa nhỏ: byte-java

Trong khi làm việc với dự án trước đó của tôi, tôi đã tạo ra bộ công cụ nhỏ này để làm việc với các byte trong Java. Nó không có phụ thuộc bên ngoài và tương thích với Java 7+. Nó bao gồm, trong số những người khác, một bộ giải mã / giải mã HEX được kiểm tra rất nhanh:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

Bạn có thể kiểm tra nó trên Github: byte-java .

Tùy chọn 4: Codec Apache Commons

Tất nhiên là có codec 'comm commons tốt . ( ý kiến ​​cảnh báo trước ) Trong khi làm việc với dự án được nêu ở trên, tôi đã phân tích mã và khá thất vọng; rất nhiều mã không có tổ chức trùng lặp, các codec lỗi thời và kỳ lạ có lẽ chỉ hữu ích cho rất ít và quá nhiều triển khai các codec phổ biến (cụ thể là Base64). Do đó tôi sẽ đưa ra quyết định sáng suốt nếu bạn muốn sử dụng nó hoặc một giải pháp thay thế. Dù sao, nếu bạn vẫn muốn sử dụng nó, đây là đoạn mã:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Tùy chọn 5: ổi Google

Thường xuyên hơn không bạn đã có Guava như một phụ thuộc. Nếu vậy chỉ cần sử dụng:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Tùy chọn 6: Bảo mật mùa xuân

Nếu bạn sử dụng khung Spring với Spring Security, bạn có thể sử dụng như sau:

import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));

Lựa chọn 7: Lâu đài Bouncy

Nếu bạn đã sử dụng khung bảo mật Bouncy Castle, bạn có thể sử dụng tiện Hexích của nó :

import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);

Không thực sự Tùy chọn 8: Tương thích Java 9+ hoặc 'Không sử dụng JAXBs javax / xml / bind / DatatypeConverter'

Trong các phiên bản Java trước (8 trở xuống), mã Java cho JAXB được bao gồm dưới dạng phụ thuộc thời gian chạy. Vì Java 9 và mô đun hóa ghép hình, mã của bạn không thể truy cập mã khác ngoài mô-đun mà không cần khai báo rõ ràng. Vì vậy, hãy lưu ý nếu bạn nhận được một ngoại lệ như:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

khi chạy trên JVM với Java 9+. Nếu vậy thì chuyển đổi triển khai sang bất kỳ giải pháp thay thế nào ở trên. Xem thêm câu hỏi này .


Điểm chuẩn vi mô

Dưới đây là kết quả từ một mảng byte mã hóa chuẩn JMH đơn giản có kích thước khác nhau . Các giá trị là hoạt động mỗi giây, vì vậy cao hơn là tốt hơn. Lưu ý rằng điểm chuẩn vi mô rất thường không đại diện cho hành vi trong thế giới thực, vì vậy hãy lấy những kết quả này bằng một hạt muối.

| Name (ops/s)         |    16 byte |    32 byte |  128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger     |  2,088,514 |  1,008,357 |   133,665 |       4 |
| Opt2/3: Bytes Lib    | 20,423,170 | 16,049,841 | 6,685,522 |     825 |
| Opt4: Apache Commons | 17,503,857 | 12,382,018 | 4,319,898 |     529 |
| Opt5: Guava          | 10,177,925 |  6,937,833 | 2,094,658 |     257 |
| Opt6: Spring         | 18,704,986 | 13,643,374 | 4,904,805 |     601 |
| Opt7: BC             |  7,501,666 |  3,674,422 | 1,077,236 |     152 |
| Opt8: JAX-B          | 13,497,736 |  8,312,834 | 2,590,940 |     346 |

Thông số kỹ thuật: JDK 8u202, i7-7700K, Win10, Ram 24GB. Xem điểm chuẩn đầy đủ ở đây .



21

Tôi sẽ sử dụng một cái gì đó như thế này cho chiều dài cố định, như băm:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

2
Cảm ơn bạn, điều này là rất súc tích và thích hợp.
Deepan Bohhu Babu

18

Tôi đã tìm thấy ba cách khác nhau ở đây: http://www.rgagnon.com/javadetails/java-0596.html

Người thanh lịch nhất, như anh ấy cũng lưu ý, tôi nghĩ là cái này:

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
        return null;
    }
    final StringBuilder hex = new StringBuilder( 2 * raw.length );
    for ( final byte b : raw ) {
        hex.append(HEXES.charAt((b & 0xF0) >> 4))
            .append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

Các phương thức khác đang chạy trên mẫu 64 byte của tôi trong 5ms, phương thức này chạy trong 0ms. Có lẽ tốt nhất cho việc thiếu bất kỳ hàm String nào khác như định dạng.
Joseph Lust

if (raw == null) return nullkhông thất bại nhanh Tại sao bạn sẽ sử dụng một nullchìa khóa?
Maarten Bodewes

Tôi cho rằng đó là một thói quen để xác nhận đầu vào. Trong trường hợp này, chúng tôi ngăn chặn mọi ngoại lệ tham chiếu Null và để nó cho người gọi xử lý dữ liệu xấu.
Michael Bisbjerg

16

Với chi phí nhỏ để lưu trữ bảng tra cứu, việc thực hiện này rất đơn giản và rất nhanh.

 private static final char[] BYTE2HEX=(
    "000102030405060708090A0B0C0D0E0F"+
    "101112131415161718191A1B1C1D1E1F"+
    "202122232425262728292A2B2C2D2E2F"+
    "303132333435363738393A3B3C3D3E3F"+
    "404142434445464748494A4B4C4D4E4F"+
    "505152535455565758595A5B5C5D5E5F"+
    "606162636465666768696A6B6C6D6E6F"+
    "707172737475767778797A7B7C7D7E7F"+
    "808182838485868788898A8B8C8D8E8F"+
    "909192939495969798999A9B9C9D9E9F"+
    "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
    "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
    "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
    "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
    "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
    "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
   ; 

  public static String getHexString(byte[] bytes) {
    final int len=bytes.length;
    final char[] chars=new char[len<<1];
    int hexIndex;
    int idx=0;
    int ofs=0;
    while (ofs<len) {
      hexIndex=(bytes[ofs++] & 0xFF)<<1;
      chars[idx++]=BYTE2HEX[hexIndex++];
      chars[idx++]=BYTE2HEX[hexIndex];
    }
    return new String(chars);
  }

6
Tại sao không khởi tạo BYTE2HEXmảng với một forchu kỳ đơn giản ?
icza

@icza Điều đó thậm chí có thể xảy ra với trường tĩnh (hay còn gọi là hằng số) không?
nevelis

1
@nevelis Nó có thể được chỉ định trong một static { }khối.
マ ル ち だ

1
@icza bởi vì nó nhanh hơn để mã hóa bảng tra cứu hơn là tạo nó. Ở đây độ phức tạp của bộ nhớ được giao dịch với độ phức tạp thời gian, tức là. cần nhiều bộ nhớ hơn nhưng nhanh hơn (mỗi giây một chút)
Patrick Favre

8

Còn cái này thì sao?

    String byteToHex(final byte[] hash)
    {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

3

Chúng ta không cần sử dụng bất kỳ thư viện bên ngoài hoặc để viết mã dựa trên các vòng lặp và hằng số.
Chỉ đủ điều này:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);

1
Điều này rất giống với Câu trả lời của ever bối rối.
Scratte

2

Tôi thích sử dụng này:

final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
    char[] hexChars = new char[count * 2];
    for ( int j = 0; j < count; j++ ) {
        int v = bytes[j+offset] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

Nó là một chút thích ứng linh hoạt hơn của câu trả lời được chấp nhận. Cá nhân, tôi giữ cả câu trả lời được chấp nhận và sự quá tải này cùng với nó, có thể sử dụng trong nhiều ngữ cảnh hơn.


Câu hỏi ban đầu là cho byte [] thành String. Nhìn hex đến byte [] hoặc hỏi một câu hỏi khác, @NonExistent.
Bamaco

2

Tôi thường sử dụng phương pháp sau cho câu lệnh debuf, nhưng tôi không biết liệu đó có phải là cách tốt nhất để làm hay không

private static String digits = "0123456789abcdef";

public static String toHex(byte[] data){
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i != data.length; i++)
    {
        int v = data[i] & 0xff;
        buf.append(digits.charAt(v >> 4));
        buf.append(digits.charAt(v & 0xf));
    }
    return buf.toString();
}

2
Nếu trình gỡ lỗi của bạn có một ngày tồi tệ, hãy thử truy cập vào phần khởi tạo StringBuilder với một số ký tự để hỗ trợ : StringBuilder buf = new StringBuilder(data.length * 2);.
greybeard

2

Ok, có rất nhiều cách để làm điều này, nhưng nếu bạn quyết định sử dụng thư viện, tôi sẽ đề nghị chọc vào dự án của bạn để xem có gì đã được thực hiện trong thư viện đã là một phần của dự án của bạn trước khi thêm thư viện mới không chỉ để làm điều này Ví dụ: nếu bạn chưa có

org.apache.commons.codec.binary.Hex

có lẽ bạn có ...

org.apache.xerces.impl.dv.util.HexBin


2

Nếu bạn đang sử dụng khung bảo mật Spring, bạn có thể sử dụng:

import org.springframework.security.crypto.codec.Hex

final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

2

Thêm một jar tiện ích cho chức năng đơn giản là lựa chọn không tốt. Thay vào đó lắp ráp các lớp tiện ích của riêng bạn. sau đây có thể thực hiện nhanh hơn.

public class ByteHex {

    public static int hexToByte(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 String[] byteToHexTable = new String[]
    {
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
        "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
        "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
        "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
        "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
        "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
        "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
        "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
        "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
        "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
        "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
    };

    private static final String[] byteToHexTableLowerCase = new String[]
    {
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
        "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
        "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
        "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
        "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
        "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
        "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
        "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
        "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
        "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
        "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
    };

    public static String byteToHex(byte b){
        return byteToHexTable[b & 0xFF];
    }

    public static String byteToHex(byte[] bytes){
        if(bytes == null) return null;
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
        return sb.toString();
    }

    public static String byteToHex(short[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
        return sb.toString();
    }

    public static String byteToHexLowerCase(byte[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
        return sb.toString();
    }

    public static byte[] hexToByte(String hexString) {
        if(hexString == null) return null;
        byte[] byteArray = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
        }
        return byteArray;
    }

    public static byte hexPairToByte(char ch1, char ch2) {
        return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
    }


}

1

Một biến thể nhỏ của giải pháp được đề xuất bởi @maybewecouldstealavan, cho phép bạn kết hợp trực quan N byte với nhau trong chuỗi hex đầu ra:

 final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 final static char BUNDLE_SEP = ' ';

public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
        char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
        for (int j = 0, k = 1; j < bytes.length; j++, k++) {
                int v = bytes[j] & 0xFF;
                int start = (j * 2) + j/bundleSize;

                hexChars[start] = HEX_ARRAY[v >>> 4];
                hexChars[start + 1] = HEX_ARRAY[v & 0x0F];

                if ((k % bundleSize) == 0) {
                        hexChars[start + 2] = BUNDLE_SEP;
                }   
        }   
        return new String(hexChars).trim();    
}

Đó là:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E

bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

1

Không thể tìm thấy bất kỳ giải pháp nào trên trang này mà không

  1. Sử dụng một vòng lặp
  2. Sử dụng javax.xml.bind.DatatypeConverter để biên dịch tốt nhưng thường ném java.lang.NoClassDefFoundError khi chạy.

Đây là một giải pháp không có sai sót ở trên (không có lời hứa nào của tôi không có lỗi nào khác)

import java.math.BigInteger;

import static java.lang.System.out;
public final class App2 {
    // | proposed solution.
    public static String encode(byte[] bytes) {          
        final int length = bytes.length;

        // | BigInteger constructor throws if it is given an empty array.
        if (length == 0) {
            return "00";
        }

        final int evenLength = (int)(2 * Math.ceil(length / 2.0));
        final String format = "%0" + evenLength + "x";         
        final String result = String.format (format, new BigInteger(bytes));

        return result;
    }

    public static void main(String[] args) throws Exception {
        // 00
        out.println(encode(new byte[] {})); 

        // 01
        out.println(encode(new byte[] {1})); 

        //203040
        out.println(encode(new byte[] {0x20, 0x30, 0x40})); 

        // 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
        out.println(encode("All your base are belong to us.".getBytes()));
    }
}   

Tôi không thể có được điều này dưới 62 opcodes, nhưng nếu bạn có thể sống mà không có 0 đệm trong trường hợp byte đầu tiên nhỏ hơn 0x10, thì giải pháp sau chỉ sử dụng 23 opcode. Thực sự cho thấy các giải pháp "dễ tự thực hiện" như "pad với số 0 nếu độ dài chuỗi là số lẻ" có thể trở nên khá tốn kém nếu triển khai riêng không có sẵn (hoặc trong trường hợp này, nếu BigInteger có tùy chọn tiền tố với số không trong toString).

public static String encode(byte[] bytes) {          
    final int length = bytes.length;

    // | BigInteger constructor throws if it is given an empty array.
    if (length == 0) {
        return "00";
    }

    return new BigInteger(bytes).toString(16);
}

1

Giải pháp của tôi dựa trên giải pháp của mayweCouldStealAVan, nhưng không dựa vào bất kỳ bảng tra cứu được phân bổ bổ sung nào. Nó không sử dụng bất kỳ hack 'int-to-char' nào (thực ra là Character.forDigit()vậy, thực hiện một số so sánh để kiểm tra xem chữ số thực sự là gì) và do đó có thể chậm hơn một chút. Xin vui lòng sử dụng nó bất cứ nơi nào bạn muốn. Chúc mừng.

public static String bytesToHex(final byte[] bytes)
{
    final int numBytes = bytes.length;
    final char[] container = new char[numBytes * 2];

    for (int i = 0; i < numBytes; i++)
    {
        final int b = bytes[i] & 0xFF;

        container[i * 2] = Character.forDigit(b >>> 4, 0x10);
        container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
    }

    return new String(container);
}

0

// Chuyển byte hiệu quả hơn // Bạn cũng có thể sử dụng byte này

public static String getHexString (String s) 
{
    byte[] buf = s.getBytes();

    StringBuffer sb = new StringBuffer();

    for (byte b:buf)
    {
        sb.append(String.format("%x", b));
    }


        return sb.toString();
}

0

Nếu bạn đang tìm kiếm một mảng byte chính xác như thế này cho python, tôi đã chuyển đổi triển khai Java này thành python.

class ByteArray:

@classmethod
def char(cls, args=[]):
    cls.hexArray = "0123456789ABCDEF".encode('utf-16')
    j = 0
    length = (cls.hexArray)

    if j < length:
        v = j & 0xFF
        hexChars = [None, None]
        hexChars[j * 2] = str( cls.hexArray) + str(v)
        hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
        # Use if you want...
        #hexChars.pop()

    return str(hexChars)

array = ByteArray()
print array.char(args=[])

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

0

Đây là một java.util.Base64triển khai giống như (một phần), nó không đẹp sao?

public class Base16/*a.k.a. Hex*/ {
    public static class Encoder{
        private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        private boolean upper;
        public Encoder(boolean upper) {
            this.upper=upper;
        }
        public String encode(byte[] data){
            char[] value=new char[data.length*2];
            char[] toHex=upper?toUpperHex:toLowerHex;
            for(int i=0,j=0;i<data.length;i++){
                int octet=data[i]&0xFF;
                value[j++]=toHex[octet>>4];
                value[j++]=toHex[octet&0xF];
            }
            return new String(value);
        }
        static final Encoder LOWER=new Encoder(false);
        static final Encoder UPPER=new Encoder(true);
    }
    public static Encoder getEncoder(){
        return Encoder.LOWER;
    }
    public static Encoder getUpperEncoder(){
        return Encoder.UPPER;
    }
    //...
}

0
private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(2*length);

        for (int i = 0 ; i < length ; i++) {
            int b;

            b = 0x0f & (bytes[i] >> 4);
            ret.append("0123456789abcdef".charAt(b));

            b = 0x0f & bytes[i];
            ret.append("0123456789abcdef".charAt(b));
        }

        return ret.toString();
    }

0
Converts bytes data to hex characters

@param bytes byte array to be converted to hex string
@return byte String in hex format

private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}
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.