Home : Course Map : Chapter 9 : Java : Tech :
Input/Output for the Histogram Class:
Application Demo
JavaTech
Course Map
Chapter 9

Introduction
Overview
Streams
Wrappers,Buffers
Console I/O
  Text Output 
     Demo 1

  Formatter/printf()
     Demo 2

  Tex 2t Input
     Demo 3

  Scanner
     
Demo 4
File Class
  File I/O
  File Output-Text
     Demo 5

  Formatter to File
     Demo 6

  File Input - Text
    Demo 7

  Scanner - Files
     Demo 8

  File I/O - Binary
     Demo 9
   Demo 10
File Chooser Dialog
  Demo 11

Character Codes
  Demo 12
   Demo13
Object I/O
Types to Bytes
Stream Filters
Other I/O Topics
Exercises

    Supplements
Character I/O
  Demo 1   Demo 2
Random Access
  Demo 3
ZIP/GZIP Streams
  Demo 4
Piped Streams
  Demo 5
NIO Framework
More NIO
  Demo 6

     About JavaTech
     Codes List
     Exercises
     Feedback
     References
     Resources
     Tips
     Topic Index
     Course Guide
     What's New

This demonstration program illustrates the Getter/Setter approach to histogram I/O discussed in the previous section. It uses get methods in the Histogram class to obtain the necessary data to save to the disk file. When the data is read from a histogram file, the set methods place this data into an instance of the histogram.

The demonstration application shown below employs several techniques involving Java I/O:

  • Byte Array Streams - we use the ByteArrayOutputStream and ByteArrayInputStream to illustrate how a byte array can become the destination and source for streamed I/O. We use these classes to create a byte array to hold the different types of data obtained from the histogram. We wrap these streams in a DataOutputStream and a DataInputStream , respectively, so as to write and read the data for different types to and from the byte array. (See Chapter 9: Supplements: More NIO for an alternative approach.)

  • Binary I/O - we use FileOutputStream and FileInputStream objects wrapped in buffered stream objects to write and read the byte arrays with the histogram data to and from disk files.

  • JFileChooser - the file chooser dialog provides a selection of directories and files for output and input.

Since the browser's JVM blocks access to the local disk for applets, we only provide an application version of this demonstration.

The program uses code from the Histogram display program in Chapter 7: Tech : Histogram UI and combines it with the frame and chooser demonstrator in Chapter 9: Java : File Chooser. We split off the I/O related methods into a class called HistIOTools, so that the methods, which are declared static, can be used with other programs.


HistIOApp Application Frame

HistIOApp.java - This application creates a histogram and fills it with a Guassian generated random values. The menu bar offers the options to Save the histogram to a file or to open a file to read a histogram from. It uses the static methods in HistIOTools class to do most of these tasks.

+ New class:

HistIOTools.java - contains several static methods used to write and read histograms to disk files.

Saving a histogram to a file involves:

packHistogram() method uses a ByteArrayOutputStream wrapped with a Data wrapped with a ataOutputStream to save all of the histogram information (title, number of bins, etc.) and data into a byte array.

writeFile() then uses a FileOutputStream wrapped with BufferedOutputStream to send the byte array to the file.

Opening a histogram from a file reverses this.

readFile() uses a FileInputStream() wrapped with a BufferedInputStream to obtain the file data in a byte array.

unpackHistogram() method wraps the array with a ByteArrayInputStream, which is in turned wrapped with a DataInputStream to obtain the histogram information and data.

There are also overloaded versions of readFile() and writeFile() that open JFileChooser dialogs to select a file.

HstFilter.java - Used by the JFileChooser to list histogram type files (.hst).

+ Previous classes:
Chapter 6:Tech: Histogram.java, HistPanel.java
Chapter 6:Tech: PlotPanel.java, PlotFormat.java

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

/**
  * Demonstrate streaming I/O by saving and
  * reading in histograms.
**/
public class HistIOApp extends JFrame
       implements ActionListener
{
  JMenuItem fMenuOpen = null;
  JMenuItem fMenuSave  = null;
  JMenuItem fMenuClose = null;

  // Use the HistPanel JPanel subclass here
  HistPanel fOutputPanel = null;

  Histogram fHistogram = null;
  int fNumDataPoints = 100;

  // A text field for input strings
  JTextField fTextField = null;

  //Buttons
  JButton fGoButton;
  JButton fClearButton;

  File fFile;

  /**
    * Pass a title to the frame via the constructor
    ** argument.
   */
  HistIOApp (String title) {
    super (title);
  } // ctor

  /**
    * Create a User Interface with a HistPanel to
    * contain the Histogram object plus buttons to
    * fill and clear the histogram. A text area allows
    * for entry of the number of desired histogram entries.
   **/
  public void init () {

    Container content_pane = getContentPane ();

    // Create a menubar for the frame with File menu
    makeMenuBar ();

    // Now create components for the framed area.
    JPanel panel = new JPanel (new BorderLayout ());

    // Create a histogram with Gaussian distribution.
    makeHist ();

    // JPanel subclass here.
    fOutputPanel = new HistPanel (fHistogram);

    panel.add (fOutputPanel,BorderLayout.CENTER);

    // Use a textfield for an input parameter.
    fTextField =
      new JTextField (Integer.toString (fNumDataPoints), 10);

    // If return hit after entering text, the
    // actionPerformed will be invoked.
    fTextField.addActionListener (this);

    fGoButton = new JButton ("Go");
    fGoButton.addActionListener (this);

    fClearButton = new JButton ("Clear");
    fClearButton.addActionListener (this);

    JPanel control_panel = new JPanel ();

    control_panel.add (fTextField);
    control_panel.add (fGoButton);
    control_panel.add (fClearButton);

    panel.add (control_panel,BorderLayout.SOUTH);

    // Add text area with scrolling to the contentPane.
    content_pane.add (panel);

    setSize (400,400);

    setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

  } // init

  /** Create a menu bar with a File drop down menu. **/
  void makeMenuBar () {
    // Use the helper method makeMenuItem
    // for making the menu items and registering
    // their listener.
    JMenu m = new JMenu ("File");

    m.add (fMenuOpen  = makeMenuItem ("Open"));
    m.add (fMenuSave  = makeMenuItem ("Save"));
    m.add (fMenuClose = makeMenuItem ("Quit"));

    JMenuBar mb = new JMenuBar ();
    mb.add (m);

    setJMenuBar (mb);
  } // makeMenuBar

  /** Process the events from the buttons and menu. **/
  public void actionPerformed (ActionEvent e) {
    boolean status = false;
    Object source = e.getSource ();

    // Fill the histogram when the go button clicked or
    // when "enter" hit after a number entered into the
    // textfield
    if (source == fGoButton || source == fTextField) {
        String strNumDataPoints = fTextField.getText ();
        try {
          fNumDataPoints = Integer.parseInt (strNumDataPoints);
        }
        catch (NumberFormatException ex) {
          // Could open an error dialog here but just
          // display a message on the browser status line.
          System.out.println ("Bad input value");
          return;
        }
        // Call the makeHist () method to add data to the histogram.
        // If the first time, it also creates the histogram.
        makeHist ();
        repaint ();
    } else if (source == fClearButton) {
        fHistogram.clear ();
        repaint ();
    } else if (source == fMenuOpen) {
       // Menu item "Open" for reading in histogram files.

      // Get a file name with the chooser
      fFile = HistIOTools.openFile (this);
      // Return if no file selected
      if (fFile == null) return;

      Histogram tmp_hist = HistIOTools.readFile (fFile);
      if (tmp_hist != null)
          fHistogram = tmp_hist;
      else {
          JOptionPane.showMessageDialog (
            null, "Error opening file!", "File Open Error",
            JOptionPane.ERROR_MESSAGE);
          return;
      }
      // Update panel with new histogram.
      fOutputPanel.setHistogram (fHistogram);
      repaint ();
    }
    // Menu item Save for saving the current histgram
    // to a disk file.
    else if (source == fMenuSave) {
      // Get the file name
      fFile = HistIOTools.saveFile (this,fFile);
      // Return if no file name selected
      if (fFile == null) return;

      // Save the histogram to the file
      status = HistIOTools.writeFile (fFile,fHistogram);

      if (!status)
          JOptionPane.showMessageDialog (
            null,
            "IO error in saving file!!", "File Save Error",
              JOptionPane.ERROR_MESSAGE);
    } else if (source == fMenuClose) {
      dispose ();
    }
  } // actionPerformed

  /** Create a histogram and fill it with Gaussian data. **/
  void makeHist () {
    // Create an instance of the Random class for
    // producing our random values.
    java.util.Random r = new java.util.Random ();

    // Them method nextGaussian in the class Random produces
    // a value centered at 0.0 and a standard deviation
    // of 1.0.

    // Create an instance of our basic histogram class.
    // Make it wide enough enough to include most of the
    // gaussian values.
    if (fHistogram == null)
        fHistogram = new Histogram ("Gaussian Distribution",
                                "random values",
                                20,-3.0,3.0);

    // Fill histogram with Gaussian distribution
    for (int i=0; i < fNumDataPoints; i++) {
        double val = r.nextGaussian ();
        fHistogram.add (val);
    }
  } // makeHist


  /**
    * This "helper method" makes a menu item and then
    * registers this object as a listener to it.
    *
    * @param name menu item label.
   **/
  private JMenuItem makeMenuItem (String name) {
    JMenuItem m = new JMenuItem (name);
    m.addActionListener (this);
    return m;
  } // makeMenuItem

  /** Run as an application. **/
  public static void main (String [] args) {
   // Can pass frame title in command line arguments
    String title="HistIOApp";
    if (args.length != 0) title = args[0];
    HistIOApp f = new HistIOApp (title);
    f.init ();
    f.setVisible (true);
  } // main

} // class HistIOApp

import javax.swing.*;
import java.io.*;

/**
  * This class contains several static methods used to
  * write and read histograms to disk files.
**/
public class HistIOTools {
  // Create a Histogram type filter for the file chooser
  private static HstFilter fHstFilter = new HstFilter ();

  /**
    * Use a JFileChooser in Open mode to select files
    * to open. Use a filter for FileFilter subclass to select
    * for *.java files. If a file is selected then read the
    * file and place the string into the textarea.
   **/
  public static File openFile (JFrame frame) {
    File file = null;
    JFileChooser fc = new JFileChooser ();
    fc.setDialogTitle ("Open Histogram File");

    // Choose only files, not directories
    fc.setFileSelectionMode (JFileChooser.FILES_ONLY);

    // Start in current directory
    fc.setCurrentDirectory (new File ("."));

    // Set filter for web pages.
    fc.setFileFilter (fHstFilter);

    // Now open chooser
    int result = fc.showOpenDialog (frame);

    if (result == JFileChooser.CANCEL_OPTION) {
        return null;
    } else if (result == JFileChooser.APPROVE_OPTION) {
        file = fc.getSelectedFile ();
    } else {
        return null;
    }
    return file;
  } // openFIle


  /**
    * Use a JFileChooser in Save mode to select files
    * to open. Use a filter for FileFilter subclass to select
    * for *.java type files. If a file is selected, then write the
    * the string from the textarea into it.
    *
    * @param frame the chooser connects to this frame component.
    * @param file the inital file object for the chooser selection.
    * @param histogram Histogram object for saving.
   **/
  public static File saveFile (JFrame frame, File file){

    JFileChooser fc = new JFileChooser ();
    fc.setDialogTitle ("Save Histogram");

    // Start in current directory
    fc.setCurrentDirectory (new File ("."));

    // Set filter for web pages.
    fc.setFileFilter (fHstFilter);

    // Set to a default name for save.
    if (file !=null) fc.setSelectedFile (file);

    // Open chooser dialog
    int result = fc.showSaveDialog (frame);

    if (result == JFileChooser.CANCEL_OPTION) {
        return null;
    } else if ( result == JFileChooser.APPROVE_OPTION) {
        file = fc.getSelectedFile ();
        if (file.exists ())  {
            int response = JOptionPane.showConfirmDialog (null,
              "Overwrite existing file?","Confirm Overwrite",
               JOptionPane.OK_CANCEL_OPTION,
               JOptionPane.QUESTION_MESSAGE);
            if (response == JOptionPane.CANCEL_OPTION) return null;
        }
        return file;
    } else {
        return null;
    }

  } // saveFIle

  /**
    * Use a BufferedInputStream wrapped around a FileInputStream
    *  to read the binary data from the given file.
    *
    * @param file File object from which to locate file.
   **/
  public static Histogram readFile (File file) {

    try {
      FileInputStream in = new FileInputStream (file);
      BufferedInputStream dis =
           new BufferedInputStream (in);

      int num_data = in.available ();
      byte [] data = new byte[num_data];

      dis.read (data);
      dis.close ();

      return unpackHistogram (data);

    } catch (IOException ioe ) {
      JOptionPane.showMessageDialog (
            null,
            "Error in reading data!!\n\r"+ioe,
            "Histogram File Read Error",
            JOptionPane.ERROR_MESSAGE);
      return null;
    }

  } // readFile

  /**
    * Use a FileOutputStream wrapped inside a BufferedOutputStream,
    * to write the byte array data to the given file.
    *
    * @param file File object for the file to receive the histogram data.
   **/
  public static boolean writeFile (File file, Histogram histogram) {

    byte [] data = packHistogram (histogram);
    try {
      BufferedOutputStream out =
        new BufferedOutputStream (new FileOutputStream (file));
      out.write (data);
      out.flush ();
      out.close ();
    }
    catch  (IOException ioe) {
      JOptionPane.showMessageDialog (
                  null,
                  "Error in writing data!!\n\r"+ioe,
                  "Histogram File Save Error",
                  JOptionPane.ERROR_MESSAGE);
      return false;
    }
    return true;
  } // writeFile

  /**
    * Convert histogram data to a byte array
    * for storage using a byte array stream.
    *
    * @param hist Histogram object containing data to be packed.
   **/
  public static byte [] packHistogram (Histogram hist){
    // Create the byte array stream.
    ByteArrayOutputStream byte_out = new ByteArrayOutputStream ();

    // Wrap it in a data stream to take advantage of its
    // methods for writing different type data.
    DataOutputStream data_out = new DataOutputStream (byte_out);

    // The write methods can throw IOExceptions so must set up
    // to catch them
    try {

      // First pack the title by writing its length and then
      // the title as a char array  (2 bytes per char)
      int num_chars = hist.getTitle ().length ();
      data_out.writeInt (num_chars);
      data_out.writeChars (hist.getTitle ());

      // Next save the pack the title by writing its length and then
      // the title as a char array  (2 bytes per char)
      num_chars = hist.getXLabel ().length ();
      data_out.writeInt (num_chars);
      data_out.writeChars (hist.getXLabel ());

      // Save the bin array
      int [] bins = hist.getBins ();
      data_out.writeInt (bins.length);
      for (int i=0; i < bins.length; i++) {
          data_out.writeInt (bins[i]);
      }

      // Save underflow value.
      data_out.writeInt (hist.getValue (-1));
      // Save overflow value.
      data_out.writeInt (hist.getValue (bins.length));


      // Write the lower and upper range values
      data_out.writeDouble (hist.getLo ());
      data_out.writeDouble (hist.getHi ());

      data_out.flush ();
      data_out.close ();

      // Obtain from the ByteArrayOutputStream the byte array
      // with all of the histogram data.
      return byte_out.toByteArray ();

    }
    catch (IOException ioe) {
      JOptionPane.showMessageDialog (
            null,
            "Error in packing data!!\n\r"+ioe,
            "Histogram Data Error",
            JOptionPane.ERROR_MESSAGE);
       return null;
    }
  } // packHistogram

  /** Re-build a histogram from a byte array. **/
  public static Histogram unpackHistogram (byte [] hist_data){
    // Create byte array input stream from which to extract
    // values of different types.
    ByteArrayInputStream byte_in =
      new ByteArrayInputStream (hist_data);
    DataInputStream data_in = new DataInputStream (byte_in);

    // The read  methods can throw IOExceptions so must set up
    // to catch them
    try {
      // First read the characters for the title
      int num_chars = data_in.readInt ();
      char [] char_array = new char[num_chars];
      for (int i=0; i < num_chars; i++) {
        char_array[i] = data_in.readChar ();
      }

      String title = String.valueOf (char_array);

      // First read the characters for the horizontal label
      num_chars = data_in.readInt ();
      char_array = new char[num_chars];
      for (int i=0; i < num_chars; i++) {
        char_array[i] = data_in.readChar ();
      }

      String x_label = String.valueOf (char_array);

      // Get the bin data
      int num_bins = data_in.readInt ();
      int [] bins = new int[num_bins];
      for (int i=0; i < num_bins; i++)  {
          bins[i] = data_in.readInt ();
      }

      int under_flows = data_in.readInt ();
      int over_flows  = data_in.readInt ();

      double lo = data_in.readDouble ();
      double hi = data_in.readDouble ();

      // Create a histogram with
      Histogram hist = new Histogram (title, x_label, num_bins, lo, hi);
      // Pack the rest of the data.
      hist.pack (bins, under_flows, over_flows, lo, hi);

      return hist;

    } catch (IOException ioe) {
       JOptionPane.showMessageDialog (
            null,
            "Error in unpacking data!!\n\r"+ioe,
            "Histogram Data Error",
            JOptionPane.ERROR_MESSAGE);
       return null;
    }
  } // unpackHistogram


  /**
    * Use a ObjectOutputStream wrapped around a FileOutputStream,
    * to write a Histogram  (made Serializable) to the given file.
    *
    * @param file File object for the file to receive the histogram data.
   **/
  public static boolean writeSerialFile (File file,
                                        Histogram histogram) {

    try {
      ObjectOutputStream out =
        new ObjectOutputStream (new FileOutputStream (file));

      out.writeObject (histogram);
      out.flush ();
      out.close ();

    }
    catch (IOException ioe) {
      JOptionPane.showMessageDialog (
                  null,
                  "Error in writing data object!!\n\r"+ioe,
                  "Histogram File Save Error",
                  JOptionPane.ERROR_MESSAGE);
      return false;
    }
    return true;

  } // writeSerialFile

  /**
    *  Use a ObjectInputStream wrapped around a FileInputStream
    *  to read the Histogram object  (made Serializable
    *  from the given file.
    *
    * @param file File object from which to locate file.
   **/
  public static Histogram readSerialFile (File file) {
    try {
      FileInputStream in = new FileInputStream (file);
      ObjectInputStream obj_in = new ObjectInputStream (in);

      Histogram hist =  (Histogram) (obj_in.readObject ());
      obj_in.close ();
      return hist;
    }
    catch (ClassNotFoundException notex ) {
      JOptionPane.showMessageDialog (
            null,
            "Error in reading data!!\n\r"+notex,
            "Histogram File Read Error",
            JOptionPane.ERROR_MESSAGE);
      return null;
    }
    catch (IOException ioe ) {
      JOptionPane.showMessageDialog (
            null,
            "Error in reading data!!\n\r"+ioe,
            "Histogram File Read Error",
            JOptionPane.ERROR_MESSAGE);
      return null;
    }
  } // readSerialFile

} // class HistIOTools

 

References & Web Resources

 

Latest update: Feb.4, 2006

              Tech
Histogram I/O
Hist I/O - Get/Set
  Demo 1
Hist I/O - Objects
  Demo 2
HistogramStream
  Demo 3
Filtering Data
  Demo 4
Exercises

           Physics
Physics Model
Simulation Design
Physics Simulator
  Demo 1
Experiment Design
Experiment Sim.
  Demo 2
Analysis
Expt. + Analysis
  Demo 3
Exercises

  Part I Part II Part III
Java Core 1  2  3  4  5  6  7  8  9  10  11  12 13 14 15 16 17
18 19 20
21
22 23 24
Supplements

1  2  3  4  5  6  7  8  9  10  11  12

Tech 1  2  3  4  5  6  7  8  9  10  11  12
Physics 1  2  3  4  5  6  7  8  9  10  11  12

Java is a trademark of Sun Microsystems, Inc.