Java代码将字节转换为十六进制
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2817752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java code To convert byte to Hexadecimal
提问by Vivek
I have an array of bytes. I want each byte String of that array to be converted to its corresponding hexadecimal values.
我有一个字节数组。我希望将该数组的每个字节字符串转换为其相应的十六进制值。
Is there any function in Java to convert a byte array to Hexadecimal ?
Java 中是否有将字节数组转换为十六进制的函数?
回答by 0x2D9A3
Try this way:
试试这个方法:
byte bv = 10;
String hexString = Integer.toHexString(bv);
Dealing with array (if I understood you correctly):
处理数组(如果我理解正确的话):
byte[] bytes = {9, 10, 11, 15, 16};
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
result.append(String.format("%02X ", b));
result.append(" "); // delimiter
}
return result.toString();
As polygenelubricants mentioned, String.format()
is the right answer compare to Integer.toHexString()
(since it deals with negative numbers in a right way).
正如polygenelubricants所提到的,String.format()
是正确的答案Integer.toHexString()
(因为它以正确的方式处理负数)。
回答by Juriy
Use
用
Integer.toHexString((int)b);
回答by Kilian Foth
If you want a constant-width hex representation, i.e. 0A
instead of A
, so that you can recover the bytes unambiguously, try format()
:
如果您想要一个恒定宽度的十六进制表示,即0A
代替A
,以便您可以明确地恢复字节,请尝试format()
:
StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
result.append(String.format("%02X", bb));
}
return result.toString();
回答by polygenelubricants
byte[] bytes = {-1, 0, 1, 2, 3 };
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
System.out.println(sb.toString());
// prints "FF 00 01 02 03 "
See also
也可以看看
java.util.Formatter
syntax%[flags][width]conversion
- Flag
'0'
- The result will be zero-padded - Width
2
- Conversion
'X'
- The result is formatted as a hexadecimal integer, uppercase
- Flag
java.util.Formatter
句法%[flags][width]conversion
- 标志
'0'
- 结果将被零填充 - 宽度
2
- 转换
'X'
- 结果被格式化为十六进制整数,大写
- 标志
Looking at the text of the question, it's also possible that this is what is requested:
查看问题的文本,这也可能是请求的内容:
String[] arr = {"-1", "0", "10", "20" };
for (int i = 0; i < arr.length; i++) {
arr[i] = String.format("%02x", Byte.parseByte(arr[i]));
}
System.out.println(java.util.Arrays.toString(arr));
// prints "[ff, 00, 0a, 14]"
Several answers here uses Integer.toHexString(int)
; this is doable, but with some caveats. Since the parameter is an int
, a widening primitive conversion is performed to the byte
argument, which involves sign extension.
这里的几个答案使用Integer.toHexString(int)
; 这是可行的,但有一些警告。由于参数是 an int
,因此对参数执行扩展原语转换byte
,这涉及符号扩展。
byte b = -1;
System.out.println(Integer.toHexString(b));
// prints "ffffffff"
The 8-bit byte
, which is signed in Java, is sign-extended to a 32-bit int
. To effectively undo this sign extension, one can mask the byte
with 0xFF
.
byte
在 Java 中签名的 8 位被符号扩展为 32 位int
. 要有效地撤消此符号扩展,可以byte
使用0xFF
.
byte b = -1;
System.out.println(Integer.toHexString(b & 0xFF));
// prints "ff"
Another issue with using toHexString
is that it doesn't pad with zeroes:
使用的另一个问题toHexString
是它不会用零填充:
byte b = 10;
System.out.println(Integer.toHexString(b & 0xFF));
// prints "a"
Both factors combined should make the String.format
solution more preferrable.
结合这两个因素应该使String.format
解决方案更可取。
References
参考
- JLS 4.2.1 Integral Types and Values
- For
byte
, from-128
to127
, inclusive
- For
- JLS 5.1.2 Widening Primitive Conversion
- JLS 4.2.1 积分类型和值
- 对于
byte
,从-128
到127
,包含
- 对于
- JLS 5.1.2 扩大原语转换
回答by AzizSM
Here is a simple function to convert byte to Hexadecimal
这是一个将字节转换为十六进制的简单函数
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
回答by Jin Kwon
Creating (and destroying) a bunch of String
instances is not a good way if performance is an issue.
String
如果性能是一个问题,创建(和销毁)一堆实例不是一个好方法。
Please ignore those verbose (duplicate) arguments checking statements (if
s). That's for (another) educational purposes.
请忽略那些冗长(重复)的参数检查语句(if
s)。这是为了(另一个)教育目的。
Full maven project: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/
完整的 Maven 项目:http: //jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/
Encoding...
编码...
/**
* Encodes a single nibble.
*
* @param decoded the nibble to encode.
*
* @return the encoded half octet.
*/
protected static int encodeHalf(final int decoded) {
switch (decoded) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
return decoded + 0x30; // 0x30('0') - 0x39('9')
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
return decoded + 0x57; // 0x41('a') - 0x46('f')
default:
throw new IllegalArgumentException("illegal half: " + decoded);
}
}
/**
* Encodes a single octet into two nibbles.
*
* @param decoded the octet to encode.
* @param encoded the array to which each encoded nibbles are written.
* @param offset the offset in the array.
*/
protected static void encodeSingle(final int decoded, final byte[] encoded,
final int offset) {
if (encoded == null) {
throw new IllegalArgumentException("null encoded");
}
if (encoded.length < 2) {
// not required
throw new IllegalArgumentException(
"encoded.length(" + encoded.length + ") < 2");
}
if (offset < 0) {
throw new IllegalArgumentException("offset(" + offset + ") < 0");
}
if (offset >= encoded.length - 1) {
throw new IllegalArgumentException(
"offset(" + offset + ") >= encoded.length(" + encoded.length
+ ") - 1");
}
encoded[offset] = (byte) encodeHalf((decoded >> 4) & 0x0F);
encoded[offset + 1] = (byte) encodeHalf(decoded & 0x0F);
}
/**
* Decodes given sequence of octets into a sequence of nibbles.
*
* @param decoded the octets to encode
*
* @return the encoded nibbles.
*/
protected static byte[] encodeMultiple(final byte[] decoded) {
if (decoded == null) {
throw new IllegalArgumentException("null decoded");
}
final byte[] encoded = new byte[decoded.length << 1];
int offset = 0;
for (int i = 0; i < decoded.length; i++) {
encodeSingle(decoded[i], encoded, offset);
offset += 2;
}
return encoded;
}
/**
* Encodes given sequence of octets into a sequence of nibbles.
*
* @param decoded the octets to encode.
*
* @return the encoded nibbles.
*/
public byte[] encode(final byte[] decoded) {
return encodeMultiple(decoded);
}
Decoding...
解码...
/**
* Decodes a single nibble.
*
* @param encoded the nibble to decode.
*
* @return the decoded half octet.
*/
protected static int decodeHalf(final int encoded) {
switch (encoded) {
case 0x30: // '0'
case 0x31: // '1'
case 0x32: // '2'
case 0x33: // '3'
case 0x34: // '4'
case 0x35: // '5'
case 0x36: // '6'
case 0x37: // '7'
case 0x38: // '8'
case 0x39: // '9'
return encoded - 0x30;
case 0x41: // 'A'
case 0x42: // 'B'
case 0x43: // 'C'
case 0x44: // 'D'
case 0x45: // 'E'
case 0x46: // 'F'
return encoded - 0x37;
case 0x61: // 'a'
case 0x62: // 'b'
case 0x63: // 'c'
case 0x64: // 'd'
case 0x65: // 'e'
case 0x66: // 'f'
return encoded - 0x57;
default:
throw new IllegalArgumentException("illegal half: " + encoded);
}
}
/**
* Decodes two nibbles into a single octet.
*
* @param encoded the nibble array.
* @param offset the offset in the array.
*
* @return decoded octet.
*/
protected static int decodeSingle(final byte[] encoded, final int offset) {
if (encoded == null) {
throw new IllegalArgumentException("null encoded");
}
if (encoded.length < 2) {
// not required
throw new IllegalArgumentException(
"encoded.length(" + encoded.length + ") < 2");
}
if (offset < 0) {
throw new IllegalArgumentException("offset(" + offset + ") < 0");
}
if (offset >= encoded.length - 1) {
throw new IllegalArgumentException(
"offset(" + offset + ") >= encoded.length(" + encoded.length
+ ") - 1");
}
return (decodeHalf(encoded[offset]) << 4)
| decodeHalf(encoded[offset + 1]);
}
/**
* Encodes given sequence of nibbles into a sequence of octets.
*
* @param encoded the nibbles to decode.
*
* @return the encoded octets.
*/
protected static byte[] decodeMultiple(final byte[] encoded) {
if (encoded == null) {
throw new IllegalArgumentException("null encoded");
}
if ((encoded.length & 0x01) == 0x01) {
throw new IllegalArgumentException(
"encoded.length(" + encoded.length + ") is not even");
}
final byte[] decoded = new byte[encoded.length >> 1];
int offset = 0;
for (int i = 0; i < decoded.length; i++) {
decoded[i] = (byte) decodeSingle(encoded, offset);
offset += 2;
}
return decoded;
}
/**
* Decodes given sequence of nibbles into a sequence of octets.
*
* @param encoded the nibbles to decode.
*
* @return the decoded octets.
*/
public byte[] decode(final byte[] encoded) {
return decodeMultiple(encoded);
}
回答by ajrskelton
If you are happy to use an external library, the org.apache.commons.codec.binary.Hex
class has an encodeHex
method which takes a byte[]
and returns a char[]
. This methods is MUCH faster than the format option, and encapsulates the details of the conversion. Also comes with a decodeHex
method for the opposite conversion.
如果您乐于使用外部库,org.apache.commons.codec.binary.Hex
该类有一个encodeHex
接受 abyte[]
并返回 a 的方法char[]
。这种方法比格式选项快得多,并且封装了转换的细节。还附带了decodeHex
一种相反转换的方法。
回答by jww
Others have covered the general case. But if you have a byte array of a known form, for example a MAC address, then you can:
其他人已经涵盖了一般情况。但是如果你有一个已知形式的字节数组,例如一个 MAC 地址,那么你可以:
byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
回答by jsinglet
I am posting because none of the existing answers explain why their approaches work, which I think is really important for this problem. In some cases, this causes the proposed solution to appear unnecessarily complicated and subtle. To illustrate I will provide a fairly straightforward approach, but I'll provide a bit more detail to help illustrate whyit works.
我发帖是因为现有的答案都没有解释为什么他们的方法有效,我认为这对于这个问题非常重要。在某些情况下,这会导致建议的解决方案显得不必要地复杂和微妙。为了说明,我将提供一个相当简单的方法,但我将提供更多细节来帮助说明它为什么起作用。
First off, what are we trying to do? We want to convert a byte value (or an array of bytes) to a string which represents a hexadecimal value in ASCII. So step one is to find out exactly what a byte in Java is:
首先,我们要做什么?我们想将一个字节值(或一个字节数组)转换为一个字符串,该字符串表示 ASCII 中的十六进制值。所以第一步是找出Java中的字节到底是什么:
The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
字节数据类型是一个8 位有符号二进制补码整数。它的最小值为 -128,最大值为 127(含)。字节数据类型可用于在大型数组中节省内存,其中内存节省实际上很重要。它们也可以代替 int 使用它们的限制有助于澄清您的代码;变量范围有限的事实可以作为一种文档形式。
What does this mean? A few things: First and most importantly, it means we are working with 8-bits. So for example we can write the number 2 as 0000 0010. However, since it is two's complement, we write a negative 2 like this: 1111 1110. What is also means is that converting to hex is very straightforward. That is, you simply convert each 4 bit segment directly to hex. Note that to make sense of negative numbers in this scheme you will first need to understand two's complement. If you don't already understand two's complement, you can read an excellent explanation, here: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html
这是什么意思?一些事情:首先,也是最重要的,这意味着我们正在使用8-bits。例如,我们可以将数字 2 写为 0000 0010。但是,由于它是二进制补码,因此我们将负数 2 写成这样:1111 1110。这也意味着转换为十六进制非常简单。也就是说,您只需将每个 4 位段直接转换为十六进制。请注意,要理解此方案中的负数,您首先需要了解二进制补码。如果你还不了解二进制补码,你可以在这里阅读一个很好的解释:http: //www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html
Converting Two's Complement to Hex In General
一般将二进制补码转换为十六进制
Once a number is in two's complement it is dead simple to convert it to hex. In general, converting from binary to hex is very straightforward, and as you will see in the next two examples, you can go directly from two's complement to hex.
一旦一个数字在二进制补码中,将其转换为十六进制非常简单。一般来说,从二进制转换为十六进制非常简单,正如您将在接下来的两个示例中看到的,您可以直接从二进制补码转换为十六进制。
Examples
例子
Example 1:Convert 2 to Hex.
示例 1:将 2 转换为十六进制。
1) First convert 2 to binary in two's complement:
1) 首先将 2 转换为二进制补码:
2 (base 10) = 0000 0010 (base 2)
2) Now convert binary to hex:
2)现在将二进制转换为十六进制:
0000 = 0x0 in hex
0010 = 0x2 in hex
therefore 2 = 0000 0010 = 0x02.
Example 2:Convert -2 (in two's complement) to Hex.
示例 2:将 -2(以二进制补码形式)转换为十六进制。
1) First convert -2 to binary in two's complement:
1) 首先将 -2 转换为二进制补码:
-2 (base 10) = 0000 0010 (direct conversion to binary)
1111 1101 (invert bits)
1111 1110 (add 1)
therefore: -2 = 1111 1110 (in two's complement)
2) Now Convert to Hex:
2)现在转换为十六进制:
1111 = 0xF in hex
1110 = 0xE in hex
therefore: -2 = 1111 1110 = 0xFE.
Doing this In Java
在 Java 中这样做
Now that we've covered the concept, you'll find we can achieve what we want with some simple masking and shifting. The key thing to understand is that the byte you are trying to convert is already in two's complement.You don't do this conversion yourself. I think this is a major point of confusion on this issue. Take for example the follow byte array:
现在我们已经介绍了这个概念,您会发现我们可以通过一些简单的遮罩和移位来实现我们想要的。要理解的关键是您尝试转换的字节已经是二进制补码。您不会自己进行此转换。我认为这是这个问题上的一个主要混淆点。以下面的字节数组为例:
byte[] bytes = new byte[]{-2,2};
We just manually converted them to hex, above, but how can we do it in Java? Here's how:
我们只是手动将它们转换为十六进制,上面,但我们如何在 Java 中做到这一点?就是这样:
Step 1:Create a StringBuffer to hold our computation.
步骤 1:创建一个 StringBuffer 来保存我们的计算。
StringBuffer buffer = new StringBuffer();
Step 2:Isolate the higher order bits, convert them to hex, and append them to the buffer
步骤 2:隔离高阶位,将它们转换为十六进制,并将它们附加到缓冲区
Given the binary number 1111 1110, we can isolate the higher order bits by first shifting them over by 4, and then zeroing out the rest of the number. Logically this is simple, however, the implementation details in Java (and many languages) introduce a wrinkle because of sign extension. Essentially, when you shift a byte value, Java first converts your value to an integer, and then performs sign extension. So while you would expect 1111 1110 >> 4 to be 0000 1111, in reality, in Java it is represented as the two's complement 0xFFFFFFFF!
给定二进制数 1111 1110,我们可以通过首先将它们移位 4,然后将其余数字清零来隔离高阶位。从逻辑上讲,这很简单,但是,由于符号扩展,Java(和许多语言)中的实现细节引入了皱纹。本质上,当您移动一个字节值时,Java 首先将您的值转换为整数,然后执行符号扩展。因此,虽然您期望 1111 1110 >> 4 为 0000 1111,但实际上,在 Java 中它表示为二进制补码 0xFFFFFFFF!
So returning to our example:
所以回到我们的例子:
1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)
We can then isolate the bits with a mask:
然后我们可以用掩码隔离这些位:
1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex.
In Java we can do this all in one shot:
在 Java 中,我们可以一次性完成这一切:
Character.forDigit((bytes[0] >> 4) & 0xF, 16);
The forDigit function just maps the number you pass it onto the set of hexadecimal numbers 0-F.
forDigit 函数只是将您传递给它的数字映射到十六进制数字 0-F 的集合上。
Step 3:Next we need to isolate the lower order bits. Since the bits we want are already in the correct position, we can just mask them out:
第 3 步:接下来我们需要隔离低位。由于我们想要的位已经在正确的位置,我们可以将它们屏蔽掉:
1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.
Like before, in Java we can do this all in one shot:
和以前一样,在 Java 中,我们可以一次性完成所有这些:
Character.forDigit((bytes[0] & 0xF), 16);
Putting this all together we can do it as a for loop and convert the entire array:
将所有这些放在一起,我们可以将其作为 for 循环并转换整个数组:
for(int i=0; i < bytes.length; i++){
buffer.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16));
buffer.append(Character.forDigit((bytes[i] & 0xF), 16));
}
Hopefully this explanation makes things clearer for those of you wondering exactly what is going on in the many examples you will find on the internet. Hopefully I didn't make any egregious errors, but suggestions and corrections are highly welcome!
希望这个解释能让你们中的那些想知道在互联网上找到的许多例子中到底发生了什么的人更清楚。希望我没有犯任何严重的错误,但非常欢迎建议和更正!
回答by Crystark
The fastestway i've yet found to do this is the following:
我还发现这样做的最快方法如下:
private static final String HEXES = "0123456789ABCDEF";
static String getHex(byte[] raw) {
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();
}
It's ~ 50x faster than String.format
. if you want to test it:
它比String.format
. 如果你想测试它:
public class MyTest{
private static final String HEXES = "0123456789ABCDEF";
@Test
public void test_get_hex() {
byte[] raw = {
(byte) 0xd0, (byte) 0x0b, (byte) 0x01, (byte) 0x2a, (byte) 0x63,
(byte) 0x78, (byte) 0x01, (byte) 0x2e, (byte) 0xe3, (byte) 0x6c,
(byte) 0xd2, (byte) 0xb0, (byte) 0x78, (byte) 0x51, (byte) 0x73,
(byte) 0x34, (byte) 0xaf, (byte) 0xbb, (byte) 0xa0, (byte) 0x9f,
(byte) 0xc3, (byte) 0xa9, (byte) 0x00, (byte) 0x1e, (byte) 0xd5,
(byte) 0x4b, (byte) 0x89, (byte) 0xa3, (byte) 0x45, (byte) 0x35,
(byte) 0xd6, (byte) 0x10,
};
int N = 77777;
long t;
{
t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
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)));
}
hex.toString();
}
System.out.println(System.currentTimeMillis() - t); // 50
}
{
t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
StringBuilder hex = new StringBuilder(2 * raw.length);
for (byte b : raw) {
hex.append(String.format("%02X", b));
}
hex.toString();
}
System.out.println(System.currentTimeMillis() - t); // 2535
}
}
}
Edit: Just found something just a lil faster and that holds on one line but is not compatiblewith JRE 9. Use at your own risks
编辑:刚刚发现了一些更快的东西,并且在一行上保持不变,但与 JRE 9不兼容。使用风险自负
import javax.xml.bind.DatatypeConverter;
DatatypeConverter.printHexBinary(raw);