java 十六进制字符串 转成 byte 数组/字节数组,以及 字节数组 转成 16进制的字符串

本文提供了一种在Java中将十六进制字符串转换为字节数组,以及将字节数组转换回十六进制字符串的方法。通过具体的代码实现,帮助开发者理解和掌握十六进制数据与字节数组之间的相互转换技巧。

java 十六进制字符串 转成 byte 数组/字节数组,以及 字节数组 转成 16进制的字符串:

        // isEmpty
	public static boolean isEmpty( String str ){
		if( str == null || str.equals( "" ) ){
			return true;
		}else{
			return false;
		}
	}


	/**
	 * 16进制的字符串表示转成字节数组
	 *
	 * @param hexString     16进制格式的字符串,注意字符之间不要有空格
	 * @return    转换后的字节数组
	 */
	public static byte[] toByteArray(String hexString){
		if( isEmpty( hexString ) ){
			throw new IllegalArgumentException("this hexString must not be empty");
		}

		hexString = hexString.toLowerCase();
		final byte[] byteArray = new byte[hexString.length() / 2];
		int k = 0;

		for( int i = 0; i < byteArray.length; i++ ){   //因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
			byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
			byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
			byteArray[i] = (byte) ( high << 4 | low);
			k += 2;
		}

		return byteArray;
	}


	/**
	 * 字节数组转成16进制表示格式的字符串
	 *
	 * @param byteArray    需要转换的字节数组
	 * @return    16进制表示格式的字符串
	 */
	public static String toHexString(byte[] byteArray) {
		if( byteArray == null || byteArray.length < 1 ){
			throw new IllegalArgumentException( "this byteArray must not be null or empty" );
		}

		final StringBuilder hexString = new StringBuilder();

		for( int i = 0; i < byteArray.length; i++ ){
			if ( ( byteArray[ i ] & 0xff ) < 0x10 ) { //0~F前面不零
				hexString.append( "0" );
			}

			hexString.append( Integer.toHexString( 0xFF & byteArray[ i ] ) );
		}

		return hexString.toString().toLowerCase();
	}

 

<think>我们正在处理一个关于Java中将十六进制字符串换为byte数组并设置为UTF-8编码的问题。根据用户提供的引用和问题,我们可以这样理解: 用户希望将十六进制字符串(例如"48656c6c6f")换为byte数组,并且这个byte数组应该是UTF-8编码的字节表示。但是,这里需要注意:十六进制字符串本身可能直接表示的是字节数组(每个字节由两个十六进制字符表示),而这个字节数组的内容可以是任意二进制数据,包括UTF-8编码的文本。 然而,用户提到“设置UTF-8编码”,这暗示了用户可能希望这个十六进制字符串表示的是一串UTF-8编码的文本。因此,我们需要分两步: 1. 将十六进制字符串(不带空格,每两个字符表示一个字节换为byte数组。 2. 如果这个byte数组是UTF-8编码的文本,那么我们可以将其换为字符串(使用UTF-8解码)以验证或使用。但注意,如果用户只是想要得到UTF-8编码的字节,那么第一步得到的byte数组已经就是UTF-8编码的字节了(前提是十六进制字符串原本就是UTF-8编码的字节十六进制表示)。 但是,用户可能有一个误解:即换过程中需要指定UTF-8编码。实际上,十六进制字符串byte数组换是直接的,与编码无关。然后,如果我们想将这个byte数组解释为字符串,才需要指定编码(如UTF-8)来解码。 根据引用[^1]和[^2]提供的方法,我们可以这样实现: 首先,将十六进制字符串换为byte数组(引用[^1]提供的方法,但注意该方法要求字符串有空格分隔。而引用[^2]中的方法则没有空格,所以我们需要一个通用的方法,无论是否有空格)。 用户提供的引用[^1]中的方法要求十六进制字符串用空格分隔每个字节,但用户可能没有空格。引用[^3]提到十六进制字符串,但没有具体给出换方法。 因此,我们可以写一个通用的方法,无论是否有空格,都可以处理。但通常,我们遇到的十六进制字符串可能是连续的两个字符表示一个字节(如"48656c6c6f"),也可能是用空格分隔(如"48 65 6c 6c 6f")。我们可以先去除所有空格,然后每两个字符解析为一个字节。 步骤: 1. 去除原字符串中所有空格(如果有的话)。 2. 检查字符串长度是否为偶数(因为每个字节由两个十六进制字符表示)。 3. 每两个字符解析为一个字节。 下面提供一个方法,将十六进制字符串(可以包含空格,也可以不包含)换为byte数组: ```java public static byte[] hexStringToByteArray(String hexString) { // 移除所有空格 String cleanedHex = hexString.replaceAll("\\s", ""); int len = cleanedHex.length(); if (len % 2 != 0) { throw new IllegalArgumentException("十六进制字符串长度必须是偶数"); } byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { // 每两个字符解析为一个字节16进制) String byteStr = cleanedHex.substring(i, i + 2); data[i / 2] = (byte) Integer.parseInt(byteStr, 16); } return data; } ``` 现在,我们得到了一个byte数组。这个byte数组可能是任意二进制数据,但如果我们知道它是UTF-8编码的文本,我们可以将其换为字符串: ```java byte[] bytes = hexStringToByteArray(hexString); String text = new String(bytes, StandardCharsets.UTF_8); ``` 但是,如果用户的需求是:给定一个十六进制字符串,它表示的是某个文本的UTF-8编码的十六进制形式,然后得到对应的byte数组(这个byte数组就是UTF-8编码的字节),那么第一步就足够了。 总结: - 如果用户只是需要字节数组(用于发送等),那么使用`hexStringToByteArray`方法即可。 - 如果用户需要将十六进制字符串换为对应的UTF-8字符串(即解码),那么再使用`new String(bytes, StandardCharsets.UTF_8)`。 注意:在MQTT发送中,我们正是需要发送这个字节数组(即第一步的结果)。 下面,我们回顾一下用户最初的问题(向MQTT发送byte数组时出现“Invalid UTF-8 char”错误)以及当前的问题。用户现在可能是在构造消息负载,而这个负载是从一个十六进制字符串换来的。如果我们正确地换了,那么这个byte数组就是原始数据,直接发送即可。 但是,如果这个十六进制字符串原本表示的是非UTF-8的数据(比如图片、加密数据等),那么直接发送不会有问题(因为MQTT负载是二进制的)。而之前的错误可能是因为主题(topic)包含非UTF-8字符,或者库试图将负载当作UTF-8字符串解析(但我们已经避免,使用setPayload(byte[]))。 因此,针对当前问题:将十六进制字符串换为byte数组(UTF-8编码)的方法,实际上就是上面的`hexStringToByteArray`方法,因为它得到的byte数组就是原始字节。如果原始字节是UTF-8编码的,那么它就是UTF-8的字节序列。 最后,提供一个完整示例: ```java import java.nio.charset.StandardCharsets; public class HexToUtf8Example { public static void main(String[] args) { String hexString = "48656c6c6f20576f726c64"; // "Hello World"的UTF-8字节十六进制表示 // 换为byte数组(这个数组就是UTF-8编码的字节byte[] utf8Bytes = hexStringToByteArray(hexString); // 如果我们想验证这个byte数组对应的字符串,可以解码 String text = new String(utf8Bytes, StandardCharsets.UTF_8); System.out.println(text); // 输出: Hello World // 然后我们可以将这个byte数组用于MQTT发送 } public static byte[] hexStringToByteArray(String hexString) { String cleanedHex = hexString.replaceAll("\\s", ""); int len = cleanedHex.length(); if (len % 2 != 0) { throw new IllegalArgumentException("十六进制字符串长度必须是偶数"); } byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { String byteStr = cleanedHex.substring(i, i + 2); data[i / 2] = (byte) Integer.parseInt(byteStr, 16); } return data; } } ``` 注意:上面的例子中,十六进制字符串没有空格。如果有空格,我们的方法会自动去除。 如果用户提供的十六进制字符串是带有空格的(如"48 65 6c 6c 6f"),同样可以处理。 所以,用户只需要使用`hexStringToByteArray`方法即可得到UTF-8编码的字节数组(前提是原始十六进制字符串确实是UTF-8文本的十六进制表示)。 如果用户想要将普通的字符串(不是十六进制形式)换为UTF-8的字节数组,那更简单: ```java String text = "Hello World"; byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8); ``` 但用户的问题是要求从十六进制字符串换为byte数组(并设置UTF-8编码),所以使用的是上面提供的方法。 最后,生成相关问题: §§相关问题§§ 1. Java中如何将byte数组换为十六进制字符串? 2. 如何将普通字符串换为UTF-8编码的字节数组? 3. Java中如何处理包含空格分隔的十六进制字符串? 4. 在MQTT消息发送中,如何正确发送二进制数据? 5. Java中UTF-8编码与ASCII编码的区别是什么? </think>### Java十六进制字符串换为byte数组并设置UTF-8编码的方法 #### 核心步骤解析 1. **十六进制字符串byte数组** 使用安全换方法避免编码问题。引用[^1]提供的`hexStringToByteArray`方法直接十六进制值: ```java public static byte[] hexStringToByteArray(String hexString) { // 移除所有空格(兼容带空格或不带空格的输入) String cleanedHex = hexString.replaceAll("\\s", ""); int len = cleanedHex.length(); if (len % 2 != 0) { throw new IllegalArgumentException("十六进制字符串长度必须是偶数"); } byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { // 每两个字符解析为一个字节16进制) String byteStr = cleanedHex.substring(i, i + 2); data[i / 2] = (byte) Integer.parseInt(byteStr, 16); } return data; } ``` **关键点**: - `replaceAll("\\s", "")` 处理带空格的输入(如`"48 65 6c"`) - `Integer.parseInt(byteStr, 16)` 直接按16进制解析字节值 - 避免`getBytes()`错误(引用[^1]警告该方法会按ASCII/UTF-8码) 2. **byte数组UTF-8字符串(可选解码)** 若需验证内容或获取文本表示,使用UTF-8解码: ```java import java.nio.charset.StandardCharsets; byte[] byteArray = hexStringToByteArray("48656c6c6f"); // "Hello"的十六进制 String utf8String = new String(byteArray, StandardCharsets.UTF_8); System.out.println(utf8String); // 输出: Hello ``` #### 完整使用示例 ```java import java.nio.charset.StandardCharsets; public class HexToUtf8Converter { public static void main(String[] args) { // 示例1:基本换(无空格十六进制) String hex1 = "e4bda0e5a5bd"; // "你好"的UTF-8字节 byte[] bytes1 = hexStringToByteArray(hex1); String text1 = new String(bytes1, StandardCharsets.UTF_8); System.out.println(text1); // 输出: 你好 // 示例2:带空格的输入兼容 String hex2 = "48 65 6C 6C 6F 20 57 6F 72 6C 64"; // "Hello World" byte[] bytes2 = hexStringToByteArray(hex2); String text2 = new String(bytes2, StandardCharsets.UTF_8); System.out.println(text2); // 输出: Hello World } public static byte[] hexStringToByteArray(String hexString) { String cleanedHex = hexString.replaceAll("\\s", ""); int len = cleanedHex.length(); if (len % 2 != 0) { throw new IllegalArgumentException("十六进制字符串长度必须是偶数"); } byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { String byteStr = cleanedHex.substring(i, i + 2); data[i / 2] = (byte) Integer.parseInt(byteStr, 16); } return data; } } ``` #### 关键注意事项 1. **直接字节值** 此方法直接解析十六进制数值到字节,不经过额外编码换,确保二进制数据完整。引用[^1]强调`getBytes()`会导致ASCII/UTF-8码错误。 2. **UTF-8字符兼容性** 中文字符需3字节表示(如`"你"=e4bda0`),换后需用UTF-8解码才能正确显示(引用[^1])。 3. **错误处理** - 长度校验:确保十六进制字符串长度为偶数 - 非法字符:`Integer.parseInt`遇到非十六进制字符会抛`NumberFormatException` 4. **逆向换(byte数组十六进制)** 如需反向操作,使用引用[^2]提供的方法: ```java public static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X ", b)); // %02X保证两位十六进制 } return sb.toString().trim(); } ``` #### 应用场景 - **MQTT消息发送**:换后的`byte[]`可直接用于`MqttMessage.setPayload()` - **二进制数据处理**:加密数据、图像字节等需保持原样的场景 - **协议通信**:串口、TCP/UDP等需十六进制格式的通信协议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值