所谓的十六进制编辑器,就是把用十六进制的方式打开一个文件,其中读进来的每个字节被做为两个十六进制数看待,例如:
读入字节: 01101010; 分解成前后两个16进制数,每四个一组,就成了: 0110 1010 --> 6 A。
所以首先我们需要把文件做为字节流读入:
File file = new File(filePath);
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
byte[] a = new byte[1024];
int count = -1;
StringBuilder sb = new StringBuilder();
while ((count = in.read(a)) != -1) {
//TODO
}
in.close();
以上每次读入一个字节块,并存入数组a中。下面要做的就是把读入的每个字节都分解成两个16进制数,因此我们仅仅需要关心字节的最后8位,并分别提取出前四位和后四位,最后组合成一个16进制数即可。
提取和组合的方法相当简单,如下:
private static void convertByte2Hex(byte b, StringBuilder sb) {
int number = b & 0x00ff;
if(number<16){
sb.append(0);
}
sb.append(Integer.toHexString(number));
}
有了这个方法,上面代码的//TODO部分就可以完成了:
for (int i = 0; i < count; i++) {
convertByte2Hex(a[i], sb);
}
这样,一个文件的16进制表示就完成。例如:
package test;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("HelloWorld!");
}
}
以上类编译后生成的class文件的16进制表示为:
CA FE BA BE 00 00 00 31 00 22 07 00 02 01 00 09
74 65 73 74 2F 54 65 73 74 07 00 04 01 00 10 6A
61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01
00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 01 00
04 43 6F 64 65 0A 00 03 00 09 0C 00 05 00 06 01
00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C
65 01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C
65 54 61 62 6C 65 01 00 04 74 68 69 73 01 00 0B
4C 74 65 73 74 2F 54 65 73 74 3B 01 00 04 6D 61
69 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E
67 2F 53 74 72 69 6E 67 3B 29 56 09 00 11 00 13
07 00 12 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F
53 79 73 74 65 6D 0C 00 14 00 15 01 00 03 6F 75
74 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69
6E 74 53 74 72 65 61 6D 3B 08 00 17 01 00 0B 48
65 6C 6C 6F 57 6F 72 6C 64 21 0A 00 19 00 1B 07
00 1A 01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69
6E 74 53 74 72 65 61 6D 0C 00 1C 00 1D 01 00 07
70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61
2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01
00 04 61 72 67 73 01 00 13 5B 4C 6A 61 76 61 2F
6C 61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 0A 53
6F 75 72 63 65 46 69 6C 65 01 00 09 54 65 73 74
2E 6A 61 76 61 00 21 00 01 00 03 00 00 00 00 00
02 00 01 00 05 00 06 00 01 00 07 00 00 00 2F 00
01 00 01 00 00 00 05 2A B7 00 08 B1 00 00 00 02
00 0A 00 00 00 06 00 01 00 00 00 03 00 0B 00 00
00 0C 00 01 00 00 00 05 00 0C 00 0D 00 00 00 09
00 0E 00 0F 00 01 00 07 00 00 00 37 00 02 00 01
00 00 00 09 B2 00 10 12 16 B6 00 18 B1 00 00 00
02 00 0A 00 00 00 0A 00 02 00 00 00 09 00 08 00
0B 00 0B 00 00 00 0C 00 01 00 00 00 09 00 1E 00
1F 00 00 00 01 00 20 00 00 00 02 00 21
多试几个class,就可以发现其实开头的8个字节都是一样的,这个是描述类文件的版本的。
如果有了16进制表示,要还原来内容,用ASCII码来表示内容。我们就需要再还原出每个字节,然后把字节对应的转换成对应的字符。
假如我们有一串已经是16进制表示的字符串。根据上面的原则,每两上16进制为一组表示一个字节的内容:
public static String convertHex2ASCII(String hexString) {
int length = hexString.length();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length - 1; i += 2) {
String s = hexString.charAt(i) + "" + hexString.charAt(i + 1);
int parseInt = Integer.parseInt(s, 16);
if (parseInt < 32 && parseInt != 10) {
sb.append(" ");
} else {
sb.append((char) parseInt);
}
}
return sb.toString();
}
因为在ASCII码表中,32以下的字符都是一些不可表示字符,所以用空格代替了。