LiveGraph
data visualisation and analysis framework

org.LiveGraph.dataFile.write
Class DataStreamWriter

java.lang.Object
  extended by org.LiveGraph.dataFile.write.DataStreamWriter

public class DataStreamWriter
extends java.lang.Object

DataStreamWriter objects are used for writing files in the LiveGraph file format. DataStreamWriter does not extend java.io.Writer because the structure of the data being written is different and the making use of the methods published by the standard API class would be counter-intuitive; however, DataStreamWriter objects should be used in much the same manner as a normal Writer in an application.

The DataStreamWriter class provides methods for setting up the data file separator, adding information lines and comments to the data file, defining the number of and the labels for the data series and, eventually, for writing the data.
Before any data is sent to the writer the data series should be set up with a series of calls to addDataSeries(String). Once a dataset is written to the stream, no more data series may be added.
A dataset is written by a series of calls to one of the setDataValue(...) methods. Calls to those methods do not cause any data to be written. Instead, the values are associated with the appropriate data series and cached. In order to actually write the data to the underlying stream the method writeDataSet() must be invoked. It flushes the cache to the data stream and prepares for the processing of the next dataset.
In order to allow for concise code when using this class in applications, no methods of DataStreamWriter throw any I/O exceptions. If an IOException is thrown by the underlying stream, it is immediately caught by this class. In order to allow the application to nevertheless access and control the error handling, the methods hadIOException(), getIOException() and resetIOException() are provided.

An example of how to use this class can be found in LiveGraphDemo.

Here is a formal description of the file format produced by this class:

The LiveGraph API reads and stores data in text-based data files. The file format is based on the widely used comma-separated-values (CSV) format. LiveGraph′s file format was defined in such a way that a standard CSV file will be accepted and correctly parsed by the application (except that the very first data line might be interpreted as column headings - see below).

The format definition is as follows:

1. File is character and line based.
LiveGraph data files are text-files (i.e. not binary files). Files are read (written) on a line-by-line basis. Only after a complete line was read and parsed (or written) will the next line be considered.

2. Empty lines are ignored.
Any empty line or a line containing only white spaces is ignored without any further consequences.

3. Data values separator definition line.
The first non-empty line in a LiveGraph data file may contain an optional data values separator definition. A data values separator is a string which will separate data values in data lines.
A data values separator definition line must start and finish with the tag "##". The entire string between the opening "##" and the closing "##" will be the treated as the separator. For instance, the line "##(*)##" defines the data values separator "(*)".
A data values separator definition may not appear anywhere else than on the first non-empty line of the data file.
If the data values separator definition is omitted the default data values separator will be the string "," (comma).

4. Comment lines.
Any line where the first non-whitespace character is "#" (except for the data values separator definition line) is treated as a comment and is ignored. Note that no comments may be placed before the optional data values separator definition line.

5. File information and description lines.
Any line where the first non-whitespace character is "@" is treated as a file information or description line. A file information line does not have any effect on the interpretation of the data contained in the file; however, it may be used by a processing application to provide information to the end-user.

6. Data series labels line.
The first non-empty line in a data file which is not a data separator definition line or a comment line or a file information line is treated as data series labels line. This line defines the number and the labels of the data columns in the file. The line is split in tokens using the data values separator. The number of tokens defines the number of data columns in the file and the tokens define the labels of the columns. Note that the labels might be empty strings. For example:

     ##;##
     @Example 1
     ID;Age;;Height
     . . .
 
     @Example 2
     ,ID;Height,Age,weight,
     . . .
 

In example 1 the data separator is defined to be ";" (semicolon). 4 data series are defined here: "ID", "Age", "" and "Height" (note that the third series label here is an empty string).
In example 2 no data separator is defined, so the default separator "," (comma) is used. Note that ";" is not a separator in this case. This gives 5 data series with the following labels: "", "ID;Height", "Age", "weight" and "". Note that the first and the last series labels are empty strings. They are separated from the following (preceding) labels by the data separator.

7. Data lines.
Any non-empty line after the series labels line which is not a comment line or a file information line is treated as data values line. Data lines contain the actual data. They are parsed into tokens in the same way as the data series labels line, which means that some tokens may be empty strings. The LiveGraph API allows any string to be used as a token. (Note that the plotter application converts each token to a double precision floating point value; if a token is not a character string representing a valid decimal number, it will be converted to a not-a-number floating point value. This is interpreted by the plotter as a gap in the data series.) All data values on the same line are considered to belong to the same dataset. The data series of each value in a given dataset is determined by comparing the position index of the corresponding data token in the line to the number of the series label token in the labels line.

Here is an example data file:

     ##|##
     @File info for the user
     @More info
     #Comment
     Seconds|Dead mosquitos|Hungry frogs
     1|0|100
     600|1000|50
     1500|5000|0
     #Another comment
 

Here is another example:

     Seconds,Dead mosquitos,Hungry frogs
     1,0,100
     600,1000,50
     1500,5000,0
 

This product includes software developed by the LiveGraph project and its contributors.
(http://www.live-graph.org)
Copyright (c) 2007 G. Paperin.
All rights reserved.

File: DataStreamWriter.java

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following terms and conditions are met:

1. Redistributions of source code must retain the above acknowledgement of the LiveGraph project and its web-site, the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above acknowledgement of the LiveGraph project and its web-site, the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software or any derived software must display the following acknowledgement:
This product includes software developed by the LiveGraph project and its contributors.
(http://www.live-graph.org)

4. All advertising materials distributed in form of HTML pages or any other technology permitting active hyper-links that mention features or use of this software or any derived software must display the acknowledgment specified in condition 3 of this agreement, and in addition, include a visible and working hyper-link to the LiveGraph homepage (http://www.live-graph.org).

THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Version:
"1.1.1"
Author:
Greg Paperin (http://www.paperin.org)

Field Summary
private  boolean canAddDataSeries
          Whether new data series can still be added.
private  boolean canChangeSeparator
          Whether the data separator can still be changed.
private  int currentSeriesIndex
          Holds the series index cursor within the current dataset.
private  java.util.Map<java.lang.String,java.lang.String> dataCache
          Values of the current dataset.
private  java.util.List<java.lang.String> dataSeriesLabels
          Holds the data series labels.
private  java.io.IOException ioException
          Raised IOException (if any).
private  java.io.BufferedWriter out
          Streat writer for printing to the output stream.
private  java.lang.String separator
          The currently used data values separator.
 
Constructor Summary
DataStreamWriter(java.io.OutputStream os)
          Creates a new data writer to write on the specified stream.
 
Method Summary
 void addDataSeries(java.lang.String label)
          Defines a new data series with the specified label for this writer.
private  void checkWriteSeparatorDefinition()
          If a non-default separator was set it is written to the output stream, unless other data was already written.
private  void checkWriteSeriesLabels()
          Writes data series label information to the output stream.
 void close()
          Closes the underlying output stream.
 boolean dataSeriesExists(java.lang.String label)
          Checks whether this writer knows a data series with the specified label.
 java.lang.String getDataValue(int seriesIndex)
          Gets the data value which has been previously associated with the specified data series in the current dataset.
 java.lang.String getDataValue(java.lang.String seriesLabel)
          Gets the data value which has been previously associated with the specified data series in the current dataset.
 java.io.IOException getIOException()
          Gets the last IOException encountered by this writer.
 boolean hadIOException()
          Check whether a recent operation caused an IOException.
 void resetIOException()
          Deletes any internal state concerned with previously encountered IOExceptions.
 void setDataValue(boolean value)
          Assigns the specified value to the next data series in the current dataset.
 void setDataValue(double value)
          Assigns the specified value to the next data series in the current dataset.
 void setDataValue(float value)
          Assigns the specified value to the next data series in the current dataset.
 void setDataValue(int value)
          Assigns the specified value to the next data series in the current dataset.
 void setDataValue(int seriesIndex, boolean value)
          Assigns the specified value to the data series at the specified index in the current dataset.
 void setDataValue(int seriesIndex, double value)
          Assigns the specified value to the data series at the specified index in the current dataset.
 void setDataValue(int seriesIndex, float value)
          Assigns the specified value to the data series at the specified index in the current dataset.
 void setDataValue(int seriesIndex, int value)
          Assigns the specified value to the data series at the specified index in the current dataset.
 void setDataValue(int seriesIndex, long value)
          Assigns the specified value to the data series at the specified index in the current dataset.
 void setDataValue(int seriesIndex, java.lang.String value)
          Assigns the specified value to the data series at the specified index in the current dataset.
 void setDataValue(long value)
          Assigns the specified value to the next data series in the current dataset.
 void setDataValue(java.lang.String value)
          Assigns the specified value to the next data series in the current dataset.
 void setDataValue(java.lang.String seriesLabel, boolean value)
          Assigns the specified value to the specified data series in the current dataset.
 void setDataValue(java.lang.String seriesLabel, double value)
          Assigns the specified value to the specified data series in the current dataset.
 void setDataValue(java.lang.String seriesLabel, float value)
          Assigns the specified value to the specified data series in the current dataset.
 void setDataValue(java.lang.String seriesLabel, int value)
          Assigns the specified value to the specified data series in the current dataset.
 void setDataValue(java.lang.String seriesLabel, long value)
          Assigns the specified value to the specified data series in the current dataset.
 void setDataValue(java.lang.String seriesLabel, java.lang.String value)
          Assigns the specified value to the specified data series in the current dataset.
 void setSeparator(java.lang.String sep)
          Sets the separator between data columns and values.
 void writeComment(java.lang.String comm)
          Writes the specified comment to the output stream.
 void writeDataSet()
          Writes the current dataset to the output stream.
 void writeFileInfo(java.lang.String info)
          Writes the specified information or file description line to the output stream.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

out

private java.io.BufferedWriter out
Streat writer for printing to the output stream.


canChangeSeparator

private boolean canChangeSeparator
Whether the data separator can still be changed.


separator

private java.lang.String separator
The currently used data values separator.


canAddDataSeries

private boolean canAddDataSeries
Whether new data series can still be added.


dataSeriesLabels

private java.util.List<java.lang.String> dataSeriesLabels
Holds the data series labels.


currentSeriesIndex

private int currentSeriesIndex
Holds the series index cursor within the current dataset.


dataCache

private java.util.Map<java.lang.String,java.lang.String> dataCache
Values of the current dataset.


ioException

private java.io.IOException ioException
Raised IOException (if any).

Constructor Detail

DataStreamWriter

public DataStreamWriter(java.io.OutputStream os)
Creates a new data writer to write on the specified stream.

Parameters:
os - The stream to the the data will be written.
Method Detail

close

public void close()
Closes the underlying output stream. If any of the data values which have previously been cached by any of the setDataValue(...)-methods are not written yet, they wre written to the stream before it is closed. Once this method was invoken, no more data can be written.


setSeparator

public void setSeparator(java.lang.String sep)
Sets the separator between data columns and values. (Note - if the separator ends up being a substring of any data series label or any data value, than the parsing will lead to undefined results including possible unstable system behaviour).

Parameters:
sep - The new separator.
Throws:
java.lang.IllegalStateException - If the separator cannot be changed because other data was already written.
java.lang.IllegalArgumentException - If the specified separator is not allowed.
See Also:
DataFormatTools.isValidSeparator(String)

checkWriteSeparatorDefinition

private void checkWriteSeparatorDefinition()
If a non-default separator was set it is written to the output stream, unless other data was already written.


checkWriteSeriesLabels

private void checkWriteSeriesLabels()
Writes data series label information to the output stream.


writeComment

public void writeComment(java.lang.String comm)
Writes the specified comment to the output stream. If a data values separator has been previously set, it is written to the stream before the comment line. A sepataror may not be set after invoking this method.

Parameters:
comm - A comment line.

writeFileInfo

public void writeFileInfo(java.lang.String info)
Writes the specified information or file description line to the output stream. If a data values separator has been previously set, it is written to the stream before the information line. A sepataror may not be set after invoking this method.

Parameters:
info - An information or file description line.

dataSeriesExists

public boolean dataSeriesExists(java.lang.String label)
Checks whether this writer knows a data series with the specified label.

Parameters:
label - A data series label.
Returns:
true if a data series has been defined on this writer, false otherwise.

addDataSeries

public void addDataSeries(java.lang.String label)
Defines a new data series with the specified label for this writer. The data columns representing the data series are placed in the order in which the data series have been defined.

Parameters:
label - Label for the new data series.
Throws:
java.lang.NullPointerException - If the label is null.
java.lang.IllegalStateException - If no more data series may be defined because datasets have already been written to the output stream.

setDataValue

public void setDataValue(java.lang.String seriesLabel,
                         double value)
Assigns the specified value to the specified data series in the current dataset.

Parameters:
seriesLabel - Label of the series to which value is to be assigned.
value - A value to include in the current dataset.

setDataValue

public void setDataValue(int seriesIndex,
                         double value)
Assigns the specified value to the data series at the specified index in the current dataset.

Parameters:
seriesIndex - Column index of the series to which value is to be assigned.
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If seriesIndex < 0 or if seriesIndex >= (number of data-series defined for this writer).

setDataValue

public void setDataValue(double value)
Assigns the specified value to the next data series in the current dataset. The "next"-pointer is reset each time a dataset is written to the stream.

Parameters:
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If there are no more data series defined for this writer.

setDataValue

public void setDataValue(java.lang.String seriesLabel,
                         float value)
Assigns the specified value to the specified data series in the current dataset.

Parameters:
seriesLabel - Label of the series to which value is to be assigned.
value - A value to include in the current dataset.

setDataValue

public void setDataValue(int seriesIndex,
                         float value)
Assigns the specified value to the data series at the specified index in the current dataset.

Parameters:
seriesIndex - Column index of the series to which value is to be assigned.
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If seriesIndex < 0 or if seriesIndex >= (number of data-series defined for this writer).

setDataValue

public void setDataValue(float value)
Assigns the specified value to the next data series in the current dataset. The "next"-pointer is reset each time a dataset is written to the stream.

Parameters:
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If there are no more data series defined for this writer.

setDataValue

public void setDataValue(java.lang.String seriesLabel,
                         long value)
Assigns the specified value to the specified data series in the current dataset.

Parameters:
seriesLabel - Label of the series to which value is to be assigned.
value - A value to include in the current dataset.

setDataValue

public void setDataValue(int seriesIndex,
                         long value)
Assigns the specified value to the data series at the specified index in the current dataset.

Parameters:
seriesIndex - Column index of the series to which value is to be assigned.
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If seriesIndex < 0 or if seriesIndex >= (number of data-series defined for this writer).

setDataValue

public void setDataValue(long value)
Assigns the specified value to the next data series in the current dataset. The "next"-pointer is reset each time a dataset is written to the stream.

Parameters:
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If there are no more data series defined for this writer.

setDataValue

public void setDataValue(java.lang.String seriesLabel,
                         int value)
Assigns the specified value to the specified data series in the current dataset.

Parameters:
seriesLabel - Label of the series to which value is to be assigned.
value - A value to include in the current dataset.

setDataValue

public void setDataValue(int seriesIndex,
                         int value)
Assigns the specified value to the data series at the specified index in the current dataset.

Parameters:
seriesIndex - Column index of the series to which value is to be assigned.
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If seriesIndex < 0 or if seriesIndex >= (number of data-series defined for this writer).

setDataValue

public void setDataValue(int value)
Assigns the specified value to the next data series in the current dataset. The "next"-pointer is reset each time a dataset is written to the stream.

Parameters:
value - A value to include in the current dataset.
Throws:
java.lang.IllegalArgumentException - If there are no more data series defined for this writer.

setDataValue

public void setDataValue(java.lang.String seriesLabel,
                         boolean value)
Assigns the specified value to the specified data series in the current dataset.

Parameters:
seriesLabel - Label of the series to which value is to be assigned.
value - A value to include in the current dataset (true will be converted to 1 and false will be converted to 0).

setDataValue

public void setDataValue(int seriesIndex,
                         boolean value)
Assigns the specified value to the data series at the specified index in the current dataset.

Parameters:
seriesIndex - Column index of the series to which value is to be assigned.
value - A value to include in the current dataset (true will be converted to 1 and false will be converted to 0).
Throws:
java.lang.IllegalArgumentException - If seriesIndex < 0 or if seriesIndex >= (number of data-series defined for this writer).

setDataValue

public void setDataValue(boolean value)
Assigns the specified value to the next data series in the current dataset. The "next"-pointer is reset each time a dataset is written to the stream.

Parameters:
value - A value to include in the current dataset (true will be converted to 1 and false will be converted to 0).
Throws:
java.lang.IllegalArgumentException - If there are no more data series defined for this writer.

setDataValue

public void setDataValue(java.lang.String seriesLabel,
                         java.lang.String value)
Assigns the specified value to the specified data series in the current dataset.

Parameters:
seriesLabel - Label of the series to which value is to be assigned.
value - A value to include in the current dataset (null will be converted to the empty string "").

setDataValue

public void setDataValue(int seriesIndex,
                         java.lang.String value)
Assigns the specified value to the data series at the specified index in the current dataset.

Parameters:
seriesIndex - Column index of the series to which value is to be assigned.
value - A value to include in the current dataset (null will be converted to the empty string "").
Throws:
java.lang.IllegalArgumentException - If seriesIndex < 0 or if seriesIndex >= (number of data-series defined for this writer).

setDataValue

public void setDataValue(java.lang.String value)
Assigns the specified value to the next data series in the current dataset. The "next"-pointer is reset each time a dataset is written to the stream.

Parameters:
value - A value to include in the current dataset (null will be converted to the empty string "").
Throws:
java.lang.IllegalArgumentException - If there are no more data series defined for this writer.

getDataValue

public java.lang.String getDataValue(java.lang.String seriesLabel)
Gets the data value which has been previously associated with the specified data series in the current dataset.

Parameters:
seriesLabel - The label of the data series to query.
Returns:
The data value which has been previously associated with the specified series in the current dataset as a String or null if no value was associated with the specified data series.

getDataValue

public java.lang.String getDataValue(int seriesIndex)
Gets the data value which has been previously associated with the specified data series in the current dataset.

Parameters:
seriesIndex - Column index of the data series to query.
Returns:
The data value which has been previously associated with the specified series in the current dataset as a String or null if no value was associated with the specified data series.

writeDataSet

public void writeDataSet()
Writes the current dataset to the output stream. If a data separator was explicitly defined and not yet written, it is written to the output stream before the data. If the data series (column) labels were not yet written, they are written to the output stream before the data. After invoking this method the data separator cannot be changed and no more new data series can be defined.


hadIOException

public boolean hadIOException()
Check whether a recent operation caused an IOException.

Returns:
true if an IOException was encountered after this writer was created or after the last call to resetIOException(), false otherwise.

getIOException

public java.io.IOException getIOException()
Gets the last IOException encountered by this writer.

Returns:
If hadIOException() returns true - the last IOException encountered by this writer, otherwise - null.

resetIOException

public void resetIOException()
Deletes any internal state concerned with previously encountered IOExceptions.


LiveGraph
data visualisation and analysis framework