我有一个字节数组充满十六进制数字和打印它的简单方式是相当没有意义的,因为有许多不可打印的元素。我需要的是精确的十六进制形式:3a5f771c
当前回答
这是另一个使用Streams的方法:
private static String toHexString(byte[] bytes) {
return IntStream.range(0, bytes.length)
.mapToObj(i -> String.format("%02X", bytes[i]))
.collect(Collectors.joining());
}
其他回答
最简单的解决方案,没有外部库,没有数字常量:
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();
}
这是一个java.util。类似base64的实现,是不是很漂亮?
import java.util.Arrays;
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_CASE=new Encoder(false);
static final Encoder UPPER_CASE=new Encoder(true);
}
public static Encoder getEncoder(){
return Encoder.LOWER_CASE;
}
public static Encoder getUpperEncoder(){
return Encoder.UPPER_CASE;
}
public static class Decoder{
private static int maxIndex=102;
private static int[] toIndex;
static {
toIndex=new int[maxIndex+1];
Arrays.fill(toIndex, -1);
char[] chars={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'};
for(int i=0; i<chars.length; i++) {
toIndex[(int)chars[i]]=i;
}
}
public Decoder() {
}
public byte[] decode(String str) {
char[] value=str.toCharArray();
int start=0;
if(value.length>2 && value[0]=='0' && (value[1]=='x' || value[1]=='X')) {
start=2;
}
int byteLength=(value.length-start)/2; // ignore trailing odd char if exists
byte[] data=new byte[byteLength];
for(int i=start,j=0;i<value.length;i+=2,j++){
int i1;
int i2;
char c1=value[i];
char c2=value[i+1];
if(c1>maxIndex || (i1=toIndex[(int)c1])<0 || c2>maxIndex || (i2=toIndex[(int)c2])<0) {
throw new IllegalArgumentException("Invalid character at "+i);
}
data[j]=(byte)((i1<<4)+i2);
}
return data;
}
static final Decoder IGNORE_CASE=new Decoder();
}
public static Decoder getDecoder(){
return Decoder.IGNORE_CASE;
}
}
最近我必须实现一个十六进制转换器,以十六进制格式将字节流转储到日志中。最初我是用海克斯做的。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();
}
使用DataTypeConverter classjavax.xml.bind.DataTypeConverter
String hexString = DatatypeConverter。printHexBinary(原始字节[]);
好的,有很多方法可以做到这一点,但如果你决定使用一个库,我建议在你的项目中看看是否已经在一个库中实现了一些东西,而这个库已经是你项目的一部分,然后再添加一个新的库来做到这一点。例如,如果你还没有
org.apache.commons.codec.binary.Hex
也许你有…
org.apache.xerces.impl.dv.util.HexBin
推荐文章
- 禁用IntelliJ星(包)导入?
- 面试问题:检查一个字符串是否是另一个字符串的旋转
- 将文件加载为InputStream的不同方法
- 到底是什么导致了堆栈溢出错误?
- 为什么Android工作室说“等待调试器”如果我不调试?
- Java:路径vs文件
- ExecutorService,如何等待所有任务完成
- Maven依赖Servlet 3.0 API?
- 如何在IntelliJ IDEA中添加目录到应用程序运行概要文件中的类路径?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- Android room persistent: AppDatabase_Impl不存在
- Java的String[]在Kotlin中等价于什么?
- Intellij IDEA上的System.out.println()快捷方式
- 使用Spring RestTemplate获取JSON对象列表
- Spring JPA选择特定的列