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
|