| 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 |