仿Hex-Editor,實現簡單地二進制文件查看器JHexer

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. 更多

後續會更新對字節碼的增刪改查操作,使其更加完善

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章