ファイルダンププログラム

戻る



 手始めに、ファイル内容を16進ダンプするJavaアプリケーションを作ってみました。

 実はこれ、Javaにおけるファイル操作と、Swingのファイルチューザーの使い方を練習するために作りました。私は、個人的に使うツールとしては、何かファイルを指定してそれを加工する、というようなプログラムをよく作りますので(超ミニBASICに同梱のCMB2MOTとかCMB2Sなんてその典型ですね)、まずはそのへんのプログラムの組み方を習得しなければ、と思ったもので。
 また、ファイルダンププログラムは、なにかバイナリファイルを吐き出すようなプログラムを作ったときに、その出力が正しいかどうか確認するのに必須のツールです。作っておいて損はありません。

 なお、このプログラムは、ダンプ対象のファイルをいったんメモリに全部読みこみます。その方が、フロッピー上のファイルをダンプするときなども一度読みこんでしまえばストレスなくスクロールできるからです。ただし、あまりにも巨大なファイルを全部読みこませるのもどうかと思うので、1Mバイトを超えるファイルをダンプしようとした場合は警告メッセージを出し、最初の1Mバイトしかダンプしません。

 プログラム練習用として作ったので、いまのところ最低限の機能しかありません。スクロールバーを付けたり、任意の番地にジャンプできるようにすると実用性が増すでしょう。
 このプログラムは、ソースリストのみ公開します。これをコンパイルしてJavaバイトコードファイルにするのは簡単ですので皆さん各自で体験してください。

・コンパイルと実行

 適当なテキストエディタでソースファイル(filedump.java)を作成し、コマンドプロンプトから

と入力すればコンパイルできます。実行はコンパイル後コマンドプロンプトで

と入力します。実行すると以下のようなウインドウが現れます。


 Openボタンを押すと、以下のようなダイアログが現れるので、ダンプしたいファイルを選びます。
(最初に表示されるフォルダはWindowsの場合「マイドキュメント」になるようです。そこらへん、変えられるはずですがまだ試していません)


 とりあえず、filedump.classをダンプしてみた結果です。「-16」「+16」「-256」「+256」ボタンで番地を前後に進めることができます。
 右側の文字ダンプ、できれば日本語対応にしたいのですが文字コードの処理(ユニコードとかシフトJISとか)が面倒くさそうなのでとりあえずANKのみです。


・ソースプログラム(ファイル名 filedump.java)

import java.io.*;
import javax.swing.*;
import javax.swing.filechooser.*;
import java.awt.*;
import java.awt.event.*;

public class filedump {
  boolean Opened = false;
  byte buf[];
  long len;
  long adr;

  final long MAXLEN = 1048576;

  JFrame frm;
  JLabel lbl;

  JPanel pnlD = new JPanel() {
    public void paintComponent(Graphics g) {
      long a;
      int x,y,d;
      String s,c;
      char cs[] = {' '};

      super.paintComponent(g);

      g.setFont(new Font("Monospaced",Font.PLAIN,12));

      if(Opened) {
        a=adr;
        for(y=0;y<16;y++) {
          if(a<len) {
            s=Integer.toHexString((int)a).toUpperCase();
            s="00000000".substring(s.length())+s;
          } else {
            s="        ";
          }
          g.drawString(s,2,y*16+14);

          for(x=0;x<16;x++ ) {
            if(a<len) {
              d=((int)buf[(int)a]) & 0xff;
              s=Integer.toHexString(d).toUpperCase();
              s="00".substring(s.length())+s;

              if((d<0x20) || (d>0xde) ||
                 ((d>0x7e) && (d<0xa1))) { d=0x2e; }
              cs[0]=(char)d;
              c = new String(cs);
            } else {
              s="  ";
              c=" ";
            }
            g.drawString(s,72+x*18,y*16+14);
            g.drawString(c,382+x*8,y*16+14);
            a++;
          }
        }
      }
    }
  };

  MouseListener l_btnO = new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
      int n;
      JFileChooser fc = new JFileChooser();

      n = fc.showOpenDialog(null);
      if(n==JFileChooser.APPROVE_OPTION ) {
        frm.setCursor(new Cursor(Cursor.WAIT_CURSOR));
        try{
          RandomAccessFile f = new RandomAccessFile(fc.getSelectedFile(),"r");
          len=f.length();      
          adr=0;

          if(len>MAXLEN) {
            new JOptionPane().showMessageDialog(
              frm,new String("Can't dump whole."),"File too big!!",JOptionPane.INFORMATION_MESSAGE );
            len = MAXLEN;
          }

          buf = new byte[(int)len];
          f.readFully(buf);
          f.close();
          lbl.setText(fc.getSelectedFile().getName());
          Opened = true;

        } catch(Throwable ex) {
          new JOptionPane().showMessageDialog(
            frm,ex.getMessage(),"Exception",JOptionPane.INFORMATION_MESSAGE );
        }
        pnlD.repaint();
        frm.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
      }
    }
  };

  MouseListener l_btnFl = new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
      if(Opened && (adr+256<len)) {
        adr = adr + 16;
        pnlD.repaint();
      } 
    }
  };

  MouseListener l_btnBl = new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
      if(Opened && (adr>=16)) {
        adr = adr - 16;
        pnlD.repaint();
      } 
    }
  };

  MouseListener l_btnFp = new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
      if(Opened && (adr+256<len)) {
        adr = adr + 256;
        pnlD.repaint();
      } 
    }
  };

  MouseListener l_btnBp = new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
      if(Opened && (adr>=256)) {
        adr = adr - 256;
        pnlD.repaint();
      } 
    }
  };

  void doProg() {
    JFrame.setDefaultLookAndFeelDecorated(true);
    JDialog.setDefaultLookAndFeelDecorated(true);

    frm = new JFrame("FileDump");
    frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    lbl = new JLabel();

    JButton btnO = new JButton("Open");
    btnO.addMouseListener(l_btnO);
    JPanel pnlO = new JPanel(new BorderLayout());
    pnlO.add(btnO,BorderLayout.EAST);
    pnlO.add(lbl,BorderLayout.CENTER);

    JButton btnFl = new JButton("+16");
    btnFl.addMouseListener(l_btnFl);
    JButton btnBl = new JButton("-16");
    btnBl.addMouseListener(l_btnBl);
    JButton btnFp = new JButton("+256");
    btnFp.addMouseListener(l_btnFp);
    JButton btnBp = new JButton("-256");
    btnBp.addMouseListener(l_btnBp);

    JPanel pnlFB = new JPanel(new GridLayout(4,1));
    pnlFB.add(btnBl);
    pnlFB.add(btnFl);
    pnlFB.add(btnBp);
    pnlFB.add(btnFp);
    JPanel pnlB = new JPanel(new BorderLayout());
    pnlB.add(pnlFB,BorderLayout.NORTH);

    pnlD.setBackground(Color.WHITE);
    pnlD.setPreferredSize(new Dimension(512,256));
    frm.getContentPane().add(pnlB,BorderLayout.EAST);
    frm.getContentPane().add(pnlO,BorderLayout.SOUTH);
    frm.getContentPane().add(pnlD,BorderLayout.CENTER);
    frm.pack();
    frm.setVisible(true);
  }

  public static void main(final String args[]) {
    new filedump().doProg();
  }
}

・Javaでプログラムを組んでみた感想

 Javaの「レイアウトマネージャ」ってなんか面倒くさいですね。Delphiではそのへん、ものすごく簡単だったのですが。Javaでも「VisualEditor」というのを使うとウィンドウ内のボタンをインタラクティブに配置できるそうなのですが、それでもDelphiほど簡単になるわけではないらしいです。