Useful utility applications

Simple utility applications can be very helpful to Java developers. For example, you might need an application that generates a hexadecimal listing of a binary file. In this post, I present command-line-based and GUI-based versions of this utility application.

Command-line-based hexadecimal file dump

Q: Can you provide me with a command-line-based Java application that generates a hexadecimal listing of a binary file?

A: Listing 1 presents the contents of a HexDump application that reads the contents of a specified file and dumps this file's hexadecimal listing to standard output.

Listing 1. A command-line-based utility application for dumping a file's contents in hexadecimal to standard output

import java.io.FileInputStream;
import java.io.IOException;

public class HexDump
{
   public static void main(String[] args) throws IOException
   {
      if (args.length != 1)
      {
         System.err.println("usage: java HexDump filespec");
         return;
      }
      FileInputStream fis = new FileInputStream(args[0]);
      StringBuffer sb = new StringBuffer();
      int offset = 0;
      int ch;
      while ((ch = fis.read()) != -1)
      {
         if ((offset % 16) == 0)
            System.out.printf("%08X ", offset);
         System.out.printf("%02X ", ch);
         if (ch < 32 || ch > 127)
            sb.append('.');
         else
            sb.append((char) ch);
         if ((++offset % 16) == 0)
         {
            System.out.println(sb.toString());
            sb.setLength(0);
         }
      }
      if (sb.length() != 0)
      {
         for (int i = 0; i < 16-sb.length(); i++)
            System.out.printf("   ");
         System.out.println(sb.toString());
      }
      fis.close();
   }
}

Listing 1's main() method uses simple logic to generate a hexadecimal listing. It relies on an instance of the java.lang.StringBuffer class to store the literal characters that appear to the right of the hexadecimal values.

Compile Listing 1 (javac HexDump.java) and run this application on the resulting classfile (java HexDump HexDump.class). You should observe the following output:

00000000 CA FE BA BE 00 00 00 33 00 53 0A 00 0C 00 24 09 .......3.S....$.
00000010 00 25 00 26 08 00 27 0A 00 28 00 29 07 00 2A 0A .%.&..'..(.)..*.
00000020 00 05 00 2B 07 00 2C 0A 00 07 00 24 0A 00 05 00 ...+..,....$....
00000030 2D 09 00 25 00 2E 08 00 2F 07 00 30 0A 00 31 00 -..%..../..0..1.
00000040 32 0A 00 28 00 33 08 00 34 0A 00 07 00 35 0A 00 2..(.3..4....5..
00000050 07 00 36 0A 00 07 00 37 0A 00 07 00 38 08 00 39 ..6....7....8..9
00000060 0A 00 05 00 3A 07 00 3B 01 00 06 3C 69 6E 69 74 ....:..;...<init
00000070 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00 >...()V...Code..
00000080 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 .LineNumberTable
00000090 01 00 04 6D 61 69 6E 01 00 16 28 5B 4C 6A 61 76 ...main...([Ljav
000000A0 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 a/lang/String;)V
000000B0 01 00 0D 53 74 61 63 6B 4D 61 70 54 61 62 6C 65 ...StackMapTable
000000C0 07 00 2A 07 00 2C 01 00 0A 45 78 63 65 70 74 69 ..*..,...Excepti
000000D0 6F 6E 73 07 00 3C 01 00 0A 53 6F 75 72 63 65 46 ons..<...SourceF
000000E0 69 6C 65 01 00 0C 48 65 78 44 75 6D 70 2E 6A 61 ile...HexDump.ja
000000F0 76 61 0C 00 17 00 18 07 00 3D 0C 00 3E 00 3F 01 va.......=..>.?.
00000100 00 1C 75 73 61 67 65 3A 20 6A 61 76 61 20 48 65 ..usage: java He
00000110 78 44 75 6D 70 20 66 69 6C 65 73 70 65 63 07 00 xDump filespec..
00000120 40 0C 00 41 00 42 01 00 17 6A 61 76 61 2F 69 6F @..A.B...java/io
00000130 2F 46 69 6C 65 49 6E 70 75 74 53 74 72 65 61 6D /FileInputStream
00000140 0C 00 17 00 42 01 00 16 6A 61 76 61 2F 6C 61 6E ....B...java/lan
00000150 67 2F 53 74 72 69 6E 67 42 75 66 66 65 72 0C 00 g/StringBuffer..
00000160 43 00 44 0C 00 45 00 3F 01 00 05 25 30 38 58 20 C.D..E.?...%08X 
00000170 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A ...java/lang/Obj
00000180 65 63 74 07 00 46 0C 00 47 00 48 0C 00 49 00 4A ect..F..G.H..I.J
00000190 01 00 05 25 30 32 58 20 0C 00 4B 00 4C 0C 00 4D ...%02X ..K.L..M
000001A0 00 4E 0C 00 4F 00 50 0C 00 51 00 44 01 00 03 20 .N..O.P..Q.D... 
000001B0 20 20 0C 00 52 00 18 01 00 07 48 65 78 44 75 6D   ..R.....HexDum
000001C0 70 01 00 13 6A 61 76 61 2F 69 6F 2F 49 4F 45 78 p...java/io/IOEx
000001D0 63 65 70 74 69 6F 6E 01 00 10 6A 61 76 61 2F 6C ception...java/l
000001E0 61 6E 67 2F 53 79 73 74 65 6D 01 00 03 65 72 72 ang/System...err
000001F0 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E ...Ljava/io/Prin
00000200 74 53 74 72 65 61 6D 3B 01 00 13 6A 61 76 61 2F tStream;...java/
00000210 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 io/PrintStream..
00000220 07 70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 .println...(Ljav
00000230 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 a/lang/String;)V
00000240 01 00 04 72 65 61 64 01 00 03 28 29 49 01 00 03 ...read...()I...
00000250 6F 75 74 01 00 11 6A 61 76 61 2F 6C 61 6E 67 2F out...java/lang/
00000260 49 6E 74 65 67 65 72 01 00 07 76 61 6C 75 65 4F Integer...valueO
00000270 66 01 00 16 28 49 29 4C 6A 61 76 61 2F 6C 61 6E f...(I)Ljava/lan
00000280 67 2F 49 6E 74 65 67 65 72 3B 01 00 06 70 72 69 g/Integer;...pri
00000290 6E 74 66 01 00 3C 28 4C 6A 61 76 61 2F 6C 61 6E ntf..<(Ljava/lan
000002A0 67 2F 53 74 72 69 6E 67 3B 5B 4C 6A 61 76 61 2F g/String;[Ljava/
000002B0 6C 61 6E 67 2F 4F 62 6A 65 63 74 3B 29 4C 6A 61 lang/Object;)Lja
000002C0 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 va/io/PrintStrea
000002D0 6D 3B 01 00 06 61 70 70 65 6E 64 01 00 1B 28 43 m;...append...(C
000002E0 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 )Ljava/lang/Stri
000002F0 6E 67 42 75 66 66 65 72 3B 01 00 08 74 6F 53 74 ngBuffer;...toSt
00000300 72 69 6E 67 01 00 14 28 29 4C 6A 61 76 61 2F 6C ring...()Ljava/l
00000310 61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 09 73 65 ang/String;...se
00000320 74 4C 65 6E 67 74 68 01 00 04 28 49 29 56 01 00 tLength...(I)V..
00000330 06 6C 65 6E 67 74 68 01 00 05 63 6C 6F 73 65 00 .length...close.
00000340 21 00 16 00 0C 00 00 00 00 00 02 00 01 00 17 00 !...............
00000350 18 00 01 00 19 00 00 00 1D 00 01 00 01 00 00 00 ................
00000360 05 2A B7 00 01 B1 00 00 00 01 00 1A 00 00 00 06 .*..............
00000370 00 01 00 00 00 04 00 09 00 1B 00 1C 00 02 00 19 ................
00000380 00 00 01 66 00 06 00 06 00 00 00 D3 2A BE 04 9F ...f........*...
00000390 00 0C B2 00 02 12 03 B6 00 04 B1 BB 00 05 59 2A ..............Y*
000003A0 03 32 B7 00 06 4C BB 00 07 59 B7 00 08 4D 03 3E .2...L...Y...M.>
000003B0 2B B6 00 09 59 36 04 02 9F 00 6F 1D 10 10 70 9A +...Y6....o...p.
000003C0 00 17 B2 00 0A 12 0B 04 BD 00 0C 59 03 1D B8 00 ...........Y....
000003D0 0D 53 B6 00 0E 57 B2 00 0A 12 0F 04 BD 00 0C 59 .S...W.........Y
000003E0 03 15 04 B8 00 0D 53 B6 00 0E 57 15 04 10 20 A1 ......S...W... .
000003F0 00 0A 15 04 10 7F A4 00 0D 2C 10 2E B6 00 10 57 ........,.....W
00000400 A7 00 0B 2C 15 04 92 B6 00 10 57 84 03 01 1D 10 ...,......W.....
00000410 10 70 9A FF 9E B2 00 0A 2C B6 00 11 B6 00 04 2C .p......,......,
00000420 03 B6 00 12 A7 FF 8C 2C B6 00 13 99 00 2F 03 36 .......,...../.6
00000430 05 15 05 10 10 2C B6 00 13 64 A2 00 16 B2 00 0A .....,...d......
00000440 12 14 03 BD 00 0C B6 00 0E 57 84 05 01 A7 FF E4 .........W......
00000450 B2 00 0A 2C B6 00 11 B6 00 04 2B B6 00 15 B1 00 ...,......+.....
00000460 00 00 02 00 1A 00 00 00 5E 00 17 00 00 00 08 00 ........^.......
00000470 06 00 0A 00 0E 00 0B 00 0F 00 0D 00 1A 00 0E 00 ................
00000480 22 00 0F 00 24 00 11 00 2F 00 13 00 36 00 14 00 "...$.../...6...
00000490 4A 00 15 00 5F 00 16 00 6D 00 17 00 77 00 19 00 J..._...m...w...
000004A0 7F 00 1A 00 89 00 1C 00 93 00 1D 00 9B 00 20 00 ............. .
000004B0 A2 00 22 00 B1 00 23 00 BE 00 22 00 C4 00 24 00 .."...#..."...$.
000004C0 CE 00 26 00 D2 00 27 00 1D 00 00 00 1D 00 0A 0F ..&...'.........
000004D0 FE 00 14 07 00 1E 07 00 1F 01 FC 00 25 01 22 09 ............%.".
000004E0 07 1B FC 00 09 01 FA 00 1E 09 00 20 00 00 00 04 ........... ....
000004F0 00 01 00 21 00 01 00 22 00 00 00 02 00 23       ...!...".....#

GUI-based hexadecimal file dump

Q: Can you provide me with a GUI-based Java application that generates a hexadecimal listing of a binary file?

A: Listing 2 presents the contents of a HexDump application that reads the contents of a specified file and dumps this file's hexadecimal listing to Swing's text area component.

Listing 2. A GUI-based utility application for dumping a file's contents in hexadecimal to Swing's text area

import java.awt.EventQueue;
import java.awt.Font;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import java.util.Formatter;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class HexDump extends JFrame
{
   private final static String APP_NAME = "HexDump";
   private final static String DEFAULT_TITLE = "Untitled - "+APP_NAME;

   private File fileCurrent;

   private JFileChooser fc;

   private JTextArea ta;

   public HexDump(String[] args)
   {
      setTitle(DEFAULT_TITLE);
      setDefaultCloseOperation(EXIT_ON_CLOSE);

      fc = new JFileChooser(".");

      JMenuBar mb = new JMenuBar();

      JMenu mFile = new JMenu("File");
      JMenuItem miOpen = new JMenuItem("Open...");
      ActionListener al;
      al = new ActionListener()
      {
         @Override
         public void actionPerformed(ActionEvent ae)
         {
            doOpen();
         }
      };
      miOpen.addActionListener(al);
      mFile.add(miOpen);
      mFile.addSeparator();
      JMenuItem miExit = new JMenuItem("Exit");
      al = new ActionListener()
      {
         @Override
         public void actionPerformed(ActionEvent ae)
         {
            dispose();
         }
      };
      miExit.addActionListener(al);
      mFile.add(miExit);

      mb.add(mFile);

      setJMenuBar(mb);

      getContentPane().add(new JScrollPane(ta = new JTextArea()));
      ta.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
      ta.setFocusable(false);

      setSize(600, 400);
      setVisible(true);

      if (args.length != 0)
         doOpen(new File(args[0]));
   }

   private void doOpen()
   {
      doOpen(null);
   }

   private void doOpen(File file)
   {
      try
      {
         if (file == null)
            if (fc.showOpenDialog(HexDump.this) == JFileChooser.APPROVE_OPTION)
               file = fc.getSelectedFile();
         if (file == null)
            return;
         fc.setCurrentDirectory(file.getParentFile());
         if (file.toString().indexOf(".") == -1)
            file = new File(file+".txt");
         ta.setText(read(file));
         fileCurrent = file;
         ta.setCaretPosition(0);
         ta.requestFocus();
         setTitle(file.toString()+" - "+APP_NAME);
      }
      catch (IOException ioe)
      {
         JOptionPane.showMessageDialog(HexDump.this,
                                       "I/O error: "+ioe.getMessage(),
                                       "Alert",
                                       JOptionPane.ERROR_MESSAGE);
      }
   }

   private String read(File f) throws IOException
   {
      try (FileInputStream fis = new FileInputStream(f))
      {
         StringBuilder sb = new StringBuilder();
         int offset = 0;
         int ch;
         Formatter formatter = new Formatter();
         while ((ch = fis.read()) != -1)
         {
            if ((offset%16) == 0)
               formatter.format("%08X ", offset);
            formatter.format("%02X ", ch);
            if (ch < 32 || ch > 127)
               sb.append('.');
            else
               sb.append((char) ch);
            if ((++offset%16) == 0)
            {
               int len = sb.length();
               for (int i = 0; i < len; i++)
                  formatter.format("%c", sb.charAt(i));
               formatter.format("%n");
               sb.setLength(0);
            }
         }
         if (sb.length() != 0)
         {
            for (int i = 0; i < 16-sb.length(); i++)
               formatter.format("   ");
            formatter.format("%s%n", sb.toString());
         }
         return formatter.toString();
      }
   }

   public static void main(final String[] args)
   {
      Runnable r = new Runnable()
      {
         @Override
         public void run()
         {
            new HexDump(args);
         }
      };
      EventQueue.invokeLater(r);
   }
}

Listing 2's constructor creates a GUI and loads a file when specified by a command-line argument, assigning its hexadecimal listing to the scrollable text area. (I'm not worried about the performance implications of loading a file on the event-handling thread in this application.)

The text area's purpose is to present a read-only listing, and so it shouldn't be editable. Although passing false to setEnabled() accomplishes this task, the resulting listing is too dim to read. You can also make a text area read-only by passing false to setFocusable().

The read() method reads the file and transforms its contents into a hexadecimal listing. I use a java.util.Formatter instance to store the entire listing. I use a StringBuffer instance to temporarily store a line's literal characters (or periods).

1 2 Page 1
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.