如何将十六进制字符串转换为Java字符串?

54

为了记录日志,我们将日志转换为字节数组,然后再转换为十六进制字符串。我想把它转换回Java字符串,但我无法做到。

日志文件中的十六进制字符串看起来像:

fd00000aa8660b5b010006acdc0100000101000100010000

我该如何解码这个?

7个回答

74
在Apache Commons中使用Hex:

使用Hex

String hexString = "fd00000aa8660b5b010006acdc0100000101000100010000";    
byte[] bytes = Hex.decodeHex(hexString.toCharArray());
System.out.println(new String(bytes, "UTF-8"));

2
十六进制现在是Apache Commons Codec的一部分。 - DwB
3
这是一个依赖项:<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.12</version> </dependency> - Jacques Koorts
很容易就能发现,这个数据不是UTF-8编码的字符串,使用new String(bytes, "UTF-8")将只会产生垃圾数据。 - Holger
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> - Harsh

34
byte[] bytes = javax.xml.bind.DatatypeConverter.parseHexBinary(hexString);
String result= new String(bytes, encoding);

8
我在哪里可以找到 DatatypeConverter? - zundi
在最近的Java版本中不再是公共的。 - Jean-Alexis Aufauvre
javax.xml.bind.DatatypeConverter - telebog
编码值是什么? - gumuruh
https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html - telebog

13

您可以从字符串(十六进制)转换为字节数组,再转换为UTF-8编码的字符串确保您的十六进制字符串没有前导空格和其他字符

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

用法:

String b = "0xfd00000aa8660b5b010006acdc0100000101000100010000";
byte[] bytes = hexStringToByteArray(b);
String st = new String(bytes, StandardCharsets.UTF_8);
System.out.println(st);

如何在KitKat以下的版本中进行操作? - Kaveesh Kanwal
我可以问一下将其转换为UTF-8字符串的目的是什么吗? - user5793598

10

首先读取数据,然后将其转换为字节数组:

 byte b = Byte.parseByte(str, 16); 

接着使用 String 构造函数:

new String(byte[] bytes) 

或者如果字符集不是系统默认的:

new String(byte[] bytes, String charsetName) 

1
使用 Byte.parseByte(str, 16); 来解析十六进制数。 - gogognome
字符串构造函数需要一个字节数组而不仅仅是一个字节,我尝试过了但失败了。 - st__gen_server
@Callforeach 是的,这正是我所举的例子,byte[]代表数组而不是单个字节:new String(byte[] bytes)。 - Aleksander Gralak
我不明白...你从哪里得到了bytes字节数组? - zundi
1
@zundi,在第一行中,您只解析了单个字节。因此,您需要使用循环获取所有字节并将它们放入数组中。请查看Munene iUwej Julius的答案。他的方法正在做这件事。 - Aleksander Gralak
显示剩余2条评论

6
请尝试以下代码:

public static byte[] decode(String hex){

        String[] list=hex.split("(?<=\\G.{2})");
        ByteBuffer buffer= ByteBuffer.allocate(list.length);
        System.out.println(list.length);
        for(String str: list)
            buffer.put(Byte.parseByte(str,16));

        return buffer.array();

}

要将其转换为字符串,只需使用由解码方法返回的byte[]创建新的String。

1
我将Byte.parseByte更改为(byte)Integer.parseInteger,以允许解析大于128的数字。 - domenukk
@domenukk,应该使用Integer.parseInt(..)而不是Integer.parseInteger(..)。Byte.parseByte的实现如下{ return (byte) Integer.parseInt(Str, base);}。 - Error
@Munene 谢谢你的正则表达式。 - Error

6

如果使用JDK17或以上的版本,还有一种方法可以实现这一功能,请参阅新的HexFormat类,该类具有用于将byte[]和十六进制String相互转换的有用方法:

String hexStr ="5468697320697320616e206578616d706c6520737472696e67";
byte[] bytes = HexFormat.of().parseHex(hexStr);
String str = new String(bytes, StandardCharsets.UTF_8 /* or Charset.forName("whateverencoding")*/);

当然,您需要知道十六进制表示的精确字符编码,才能生成正确的 String 值。


5

将十六进制字符串转换为Java字符串的另一种方法:

public static String unHex(String arg) {        

    String str = "";
    for(int i=0;i<arg.length();i+=2)
    {
        String s = arg.substring(i, (i + 2));
        int decimal = Integer.parseInt(s, 16);
        str = str + (char) decimal;
    }       
    return str;
}

1
创建了许多子字符串。不太理想。 - Jonathan
将“String str”替换为StringBuffer(),如果性能是一个问题,则使用sb.append(char)。 - roninjoe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接