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. 更多
後續會更新對字節碼的增刪改查操作,使其更加完善