0. 前言
当对Java语言的理解逐渐加深时,我们会有必要对.class
文件有一定的了解,那么就少不了查看二进制文件。互联网上有很多的工具,能够帮助我们有效地查看,分析.class文件字节码。
那么我们何不自己写一个小工具来查看二进制文件呢?
当然,我们一般都是查看16进制的数据,所以这里尝试写一个最简单的二进制文件查看器,我们称之为JHexer
。
1. 设计模式
建造者(Builder)设计模式,它允许我们对对象进行链式操作,且直接使用,无需new等一系列初始化操作。
2. 代码实现
2.1 客户使用代码
public class HexDump {
public final static String FILE_NAME = "./HexDump.class";
public static void main(String... args) throws IOException {
ByteCodes.readFrom(FILE_NAME, 32).show();
}
}
ByteCodes
即是我们的核心工具类。ByteCodes.readFrom(FILE_NAME, 32)返回一个ByteCodes对象
,其中传参为文件名
,一行显示的字节数
。然后调用ByteCodes对象的show方法,打印出二进制文件的信息。
所以,客户端就这么简单,非常易用。下面介绍核心类ByteCodes
2.2 ByteCodes核心类
public class ByteCodes {
private final static int DEFAULT_ROW_SIZE = 16;
private List<Byte> byteList = new ArrayList<>();
private InputStream input;
private int rowCount;
private ByteCodes(){ }
private ByteCodes(InputStream input) throws IOException {
this(input, DEFAULT_ROW_SIZE);
}
private ByteCodes(InputStream input, int rowCount) throws IOException {
this.rowCount = rowCount;
this.input = input;
read();
}
private void read() throws IOException {
int b = -1;
while ((b = input.read()) != -1) {
byteList.add((byte)b);
}
}
public static ByteCodes readFrom(String filename) throws IOException {
return readFrom(filename, DEFAULT_ROW_SIZE);
}
public static ByteCodes readFrom(InputStream input) throws IOException {
return new ByteCodes(input);
}
public static ByteCodes readFrom(String filename, int rowCount) throws IOException {
InputStream input = new FileInputStream(filename);
return new ByteCodes(input, rowCount);
}
public static ByteCodes readFrom(InputStream input, int rowCount) throws IOException {
return new ByteCodes(input, rowCount);
}
public ByteCodes show() throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
sb.append("Address ");
for(int i = 0 ; i < rowCount ; i ++){
sb.append(String.format("%02X ", i));
}
sb.append(String.format(" | Dump %n"));
int b = -1, rowIndex = 0;
byte[] rowBytes = new byte[rowCount];
for(int i = 0 ; i < byteList.size() ; i++){
if(i % rowCount == 0){
sb.append( (i==0?"":" |") + new String(rowBytes, 0, rowIndex) + (i==0?"":"|"));
sb.append(String.format( (i==0?"":"%n") + "%08X: ", i));
rowIndex = 0;
}
sb.append( String.format("%02X ", byteList.get(i)));
byte curByte = byteList.get(i);
if(curByte == '\n' || curByte == '\r' || curByte == '\t'){
rowBytes[rowIndex++] = '.';
} else {
rowBytes[rowIndex++] = byteList.get(i);
}
}
System.out.println(sb);
return this;
}
}
DEFAULT_ROW_SIZE
常数字段表示默认一行显示16个字节。重点关注show
方法
3. 效果演示
下面是演示效果。
4. 更多
后续会更新对字节码的增删改查操作,使其更加完善