我有一个字节数组充满十六进制数字和打印它的简单方式是相当没有意义的,因为有许多不可打印的元素。我需要的是精确的十六进制形式:3a5f771c
当前回答
我们不需要使用任何外部库,也不需要基于循环和常量编写代码。 这样就够了:
byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);
其他回答
//移位字节更有效 //你也可以用这个
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();
}
最近我必须实现一个十六进制转换器,以十六进制格式将字节流转储到日志中。最初我是用海克斯做的。encodeHex已经在这里讨论过了。
但是如果你想以一种非常美观/可读的方式来表示字节数组,io.netty.buffer库可能是一个很好的用途,因为它打印出十六进制以及其中的字符串,消除了不可打印的字符。
要求是这样的,
0010 56 56 09 35 32 f0 b2 00 50 4c 45 41 53 45 20 52 VV.52...PLEASE R
0020 45 2d 45 4e 54 45 52 20 4c 41 53 54 20 54 52 41 E-ENTER LAST TRA
0030 4e 53 41 43 54 49 4f 4e 00 04 NSACTION..
使用io.netty.buffer以一种更美观的方式做到这一点的最短方法是
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
void hexDump(byte[] buf) {
ByteBuf byteBuf = Unpooled.wrappedBuffer(buf);
log.trace("Bytes received (Hex)\n" + ByteBufUtil.prettyHexDump(byteBuf.slice()));
}
如果您正在使用maven,请在pom.xml中包含以下依赖项(在netty页面中检查最新版本)
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.1.68.Final</version>
</dependency>
输出是:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000010| 40 40 b3 f3 80 f3 80 f3 80 f1 48 f1 41 f1 4e f1 |@@........H.A.N.|
|00000020| 47 f1 49 f1 4e f1 47 b5 f1 52 f1 4f f1 43 f1 4b |G.I.N.G..R.O.C.K|
|00000030| f3 80 f3 80 41 b4 40 40 f3 80 f3 80 40 f3 80 04 |....A.@@....@...|
+--------+-------------------------------------------------+----------------+
供您参考,使用答案中讨论的方法的长期方法(可能不是最有效的)是:
public static String hexDump(byte[] buf) throws DecoderException
{
ByteBuffer byteBuf = ByteBuffer.wrap(buf);
char[] result = Hex.encodeHex(byteBuf);
String bin = new String(result).toUpperCase();
String str = new String(Hex.decodeHex(bin), StandardCharsets.UTF_8);
str = str.replaceAll("[^!-~]", ".");
StringBuilder out = new StringBuilder();
int bytes_per_line = 16;
for (int pos = 0; pos < str.length(); pos += bytes_per_line) {
out.append(String.format("%04X ", pos));
if (2 * (pos + bytes_per_line) >= bin.length()) {
out.append(String.format("%-" + 2 * bytes_per_line + "s", bin.substring(2 * pos)).replaceAll("..", "$0 "));
} else {
out.append(bin.substring(2 * pos, 2 * (pos + bytes_per_line)).replaceAll("..", "$0 "));
}
out.append(" ");
if (pos + bytes_per_line > str.length()) {
out.append(str.substring(pos));
} else {
out.append(str.substring(pos, pos + bytes_per_line));
}
out.append("\n");
}
return out.toString();
}
从这里的讨论,特别是这个答案,这是我目前使用的函数:
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);
}
My own tiny benchmarks (a million bytes a thousand times, 256 bytes 10 million times) showed it to be much faster than any other alternative, about half the time on long arrays. Compared to the answer I took it from, switching to bitwise ops --- as suggested in the discussion --- cut about 20% off of the time for long arrays. (Edit: When I say it's faster than the alternatives, I mean the alternative code offered in the discussions. Performance is equivalent to Commons Codec, which uses very similar code.)
2k20版本,相对于Java 9的压缩字符串:
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
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);
}
在存储查找表的很小代价下,这个实现非常简单和快速。
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);
}
只是迭代所有字节,转换为十六进制字符串使用整数。toString(不幸的是,没有字节。toString(带基数形参)并将它们全部附加到StringBuilder中。
byte[] arr;//set it to your value
StringBuilder sb=new StringBuilder(arr.length*2);//1 byte...2 hex digits
for(int i=0;i<arr.length;i++){
sb.append(Integer.toString(arr[i],16));
}
String hexValue=sb.toString();
这类似于指针Null的答案,但它使用整数。toString而不是String。格式提高性能。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap