通常在做网络通信的程序开发时,调试时查看二进制数据非常不便,通常要用一个计算器的计算。这样查看数据时非常麻烦
下面我写了一个十六进制的数字查看程序,和大家分享一下。代码如下:
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
public class HexUtil {
/**
* 将每个字节用两位十六进制数字表示,每两个字节转换后的十六进制字符用分隔符隔开
* @param data
* @param delimiter 分隔符
* @return
*/
public static String format(byte[] data,String delimiter){
StringBuilder builder = new StringBuilder();
for (int i = 0; i < data.length; i++) {
String tmp = Integer.toHexString(data[i]&0xff);
builder.append((tmp.length()==2 ? tmp : "0"+tmp)+delimiter);
}
return builder.toString().replaceAll("\\Q"+delimiter+"\\E$", "");
}
public static String format(byte[] data){
return format(data,"");
}
/**
* 转换成十六进制查看器的显示格式
* @param data
* @return
*/
public static String formatToHexView(byte[] data){
StringBuilder builder = new StringBuilder();
if(data==null || data.length==0){return "";}
builder.append("0000 ");
for (int i = 0; i < data.length; i++) {
String tmp = Integer.toHexString(data[i]&0xff);
builder.append((tmp.length()==2 ? tmp : "0"+tmp));
if(i>0 && (i+1)%8==0 && (i+1)%16!=0){
builder.append(" ");
}else
if(i>0 && (i+1)%16==0){
//添加本行的ASCII文本
builder.append(" "+toASCII(Arrays.copyOfRange(data, i-15, i+1)));
builder.append("\n");
if(i+1<data.length){
//添加下一行的行号
String index = Integer.toHexString(i+1);
for(int k=0;k<4-index.length();k++){
builder.append("0");
}
builder.append(index);
builder.append(" ");
}
}else{
builder.append(" ");
}
if(i==data.length-1 && (i+1)%16!=0){
int remain = data.length % 16==0 ? 0 : 16-data.length % 16;
int spacenum = 0;
if(remain>0 && remain>8){
//2*remain+remain-1+2+1
spacenum = 3*remain+2;
}else if(remain>0 && remain<=8){
//2*remain+remain-1+2
spacenum = 3*remain+1;
}
for (int j = 0; j < spacenum; j++) {
builder.append(" ");
}
builder.append(toASCII(Arrays.copyOfRange(data, data.length-16+remain, data.length)));
}
}
return builder.toString().replaceAll("\\s*$", "");
}
/**
* 将数组中的ascii字符显示出来,非ascii字符用.号替代<br>
* 为了便于查看每16个字节一行显示,每8个字节加一个空格
* @param data
* @return
*/
public static String toASCII(byte[] data) {
StringBuffer buf = new StringBuffer(data.length);
for(int i=0;i<data.length;i++){
byte aValue = data[i];
if ((Character.isISOControl((char) aValue)) ||
((aValue & 0xFF) >= 0x80)) {
buf.append(".");
} else {
buf.append((char) aValue);
}
if((i+1)%8==0 && (i+1)%16!=0){
buf.append(" ");
}
}
return buf.toString();
}
/**
* 将16进制格式的文本转换成字节数组
* @param hexStr
* @return
*/
public static byte[] parse(String hexStr){
hexStr = hexStr.replaceAll("[^0-9a-fA-F]", "");
ByteArrayOutputStream bos = new ByteArrayOutputStream(200);
for (int i = 0; i < hexStr.length(); i+=2) {
int tmp = Integer.parseInt(hexStr.substring(i,i+2),16);
bos.write(tmp & 0xFF);
}
return bos.toByteArray();
}
public static void main(String[] args) {
byte[] data = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,25,26,97,98,126};
System.out.println(format(data,";"));
System.out.println(format(data));
System.out.println(formatToHexView(data));
}
}
程序的运行结果如下图所示:
第一个方法format(byte[] data,String delimiter)是将每一个字节用两位16进制格式的符号表示,每个字节之间用delimiter分隔符隔开。
formatToHexView方法的输出格式和我们用wireshark,editplus,ue,hexwin等16进制工具中显示的格式一模一样。这样是为了方便调试数据的时候查看。
parse方法是将16进制格式的字符串转换成字节数组,可以方便调试使用。