Other classes needed when writing an IOSP
To implement an IOSP, you will likely need to be familiar with the following classes:
RandomAccessFile
The class ucar.unidata.io.RandomAccessFile
is a cover for java.io.RandomAccessFile
, which it (usually) uses underneath.
It additionally implements user-settable buffer sizes, files with both big and little endianness, reading multiple Charsets
, and several other methods to improve the API.
There are subclasses of RandomAccessFile
such as HTTPRandomAccessFile
and InMemoryRandomAccessFile
, which deal with remote HTTP files
and memory resident files. Use of these subclasses is transparent to an IOSP.
A summary of the public methods that may useful to an IOSP:
public class ucar.unidata.io.RandomAccessFile {
public static final int BIG_ENDIAN;
public static final int LITTLE_ENDIAN;
// Constructors
public RandomAccessFile(String location, String mode) throws IOException;
public RandomAccessFile(String location, String mode, int buffer_size) throws IOException;
public void close() throws IOException;
public String getLocation();
public void order(int endian); // set to BIG_ENDIAN or LITTLE_ENDIAN
// file position
public long getFilePointer() throws IOException;
public long length() throws IOException;
public void seek(long filePos) throws IOException;
public int skipBytes(int nbytes) throws IOException;
// read
public int read() throws IOException;
public int read(byte[] arr) throws IOException;
public int read(byte[] arr, int start, int n) throws IOException;
public byte readByte() throws IOException;
public final double readDouble() throws IOException;
public final void readDouble(double[] arr, int start, int n) throws IOException;
public final float readFloat() throws IOException;
public final void readFloat(float[] arr, int start, int n) throws IOException;
public final int readInt() throws IOException;
public final void readInt(int[] arr, int start, int n) throws IOException;
public final long readLong() throws IOException;
public final void readLong(long[]
arr, int start, int n) throws IOException;
public final short readShort() throws IOException;
public final void readShort(short[] arr, int start, int n) throws IOException;
// read unsigned, promote to int
public final int readUnsignedShort() throws IOException;
public final int readUnsignedByte() throws IOException;
// read Strings
public final String readLine() throws IOException;
public final String readUTF() throws IOException;
public String readString(int nbytes) throws IOException;
}
Array
A ucar.ma2.Array
is a way to work with multidimensional arrays in a type and rank general way.
public abstract class Array {
public static Array factory(ucar.ma2.DataType type, int[] shape);
public static Array factory(java.lang.Class class, int[] shape);
public static Array factory(java.lang.Class class, int[] shape, java.lang.Object jarray);
public static Array factory(java.lang.Object jarray);
public int getRank();
public int[] getShape();
public long getSize();
public abstract java.lang.Class getElementType();
public abstract java.lang.Object getStorage();
public ucar.ma2.Index getIndex();
public ucar.ma2.IndexIterator getIndexIterator();
public static void arraycopy(Array, int, Array, int, int);
public Array copy();
public java.lang.Object get1DJavaArray(java.lang.Class);
public java.lang.Object copyTo1DJavaArray();
public java.lang.Object copyToNDJavaArray();
public Array flip(int);
public Array transpose(int, int);
public Array permute(int[]);
public Array reshape(int[]);
public Array reduce();
public Array reduce(int);
public Array section(java.util.List<Range> section) throws InvalidRangeException;
public Array sectionNoReduce(java.util.List<Range> section) throws InvalidRangeException;
public Array slice(int, int);
public abstract double getDouble(ucar.ma2.Index);
public abstract void setDouble(ucar.ma2.Index, double);
public abstract float getFloat(ucar.ma2.Index);
public abstract void setFloat(ucar.ma2.Index, float);
public abstract long getLong(ucar.ma2.Index);
public abstract void setLong(ucar.ma2.Index, long);
public abstract int getInt(ucar.ma2.Index);
public abstract void setInt(ucar.ma2.Index, int);
public abstract short getShort(ucar.ma2.Index);
public abstract void setShort(ucar.ma2.Index, short);
public abstract byte getByte(ucar.ma2.Index);
public abstract void setByte(ucar.ma2.Index, byte);
public abstract char getChar(ucar.ma2.Index);
public abstract void setChar(ucar.ma2.Index, char);
public abstract boolean getBoolean(ucar.ma2.Index);
public abstract void setBoolean(ucar.ma2.Index, boolean);
public abstract java.lang.Object getObject(ucar.ma2.Index);
public abstract void setObject(ucar.ma2.Index, java.lang.Object);
}
Typically an IOSP will create the underlying primitive Java array, then wrap it in an Array
using Array.factory
, for example:
// To make an Array object for data in a Variable, v:
int size = (int) v.getSize();
short[] jarray = new short[size];
// ...
// read data into jarray
// ...
Array data = Array.factory(v.getDataType(), v.getShape(), jarray);
A Section
is a container for a List
of Range
objects:
public class ucar.ma2.Section {
public List<Range> getRanges();
public int[] getOrigin();
public int[] getShape();
public int[] getStride();
...
}
When you do end up working with an Array
, you will get an Index
or IndexIterator
from the Array
to access individual elements of
the Array
. An IndexIterator
iterates over each element of the Array
in canonical order.
Array data = Array.factory(v.getDataType(), v.getShape());
IndexIterator ii = data.getIndexIterator();
while (ii.hasNext()) {
ii.setShortNext(raf.readShort());
}
Or, using an Index
:
Array data = Array.factory(DataType.DOUBLE, new int[] {5, 190});
Index ima = data.getIndex();
for (int i = 0; i < 190; i++) {
ima.set(0, i); // set index 0
for (int j = 0; j < 5; j++) {
ima.set(1, j); // set index 1
data.setDouble(ima, raf.readDouble());
}
}
If you know the rank and type of the Array
, it is both convenient and more efficient to use the rank and type specific subclasses:
ArrayDouble.D2 data = new ArrayDouble.D2(190, 5);
for (int i = 0; i < 190; i++)
for (int j = 0; j < 5; j++)
data.set(i, j, raf.readDouble());
The type specific Arrays are:
ArrayBoolean
, ArrayByte
, ArrayChar
, ArrayDouble
, ArrayFloat
, ArrayInt
, ArrayLong
, ArrayObject
and ArrayShort
.
ArrayObject
is used for the String
DataType
.
Each of these have rank specific subtypes rank 0 through rank 7, so for example:
ArrayDouble.D0
, ArrayDouble.D1
, ArrayDouble.D2
, ArrayDouble.D3
, ArrayDouble.D4
, ArrayDouble.D5
, ArrayDouble.D6
, ArrayDouble.D7
.
There is also ArrayStructure
, but this is handled differently from the numeric and String
types.
See ArrayStructures.
DataType
The class ucar.ma2.DataType
is a type-safe enumeration of data types for the CDM and include the following types:
public class ucar.ma2.DataType extends java.lang.Object{
public static final ucar.ma2.DataType BOOLEAN;
public static final ucar.ma2.DataType BYTE;
public static final ucar.ma2.DataType CHAR;
public static final ucar.ma2.DataType SHORT;
public static final ucar.ma2.DataType INT;
public static final ucar.ma2.DataType LONG;
public static final ucar.ma2.DataType FLOAT;
public static final ucar.ma2.DataType DOUBLE;
public static final ucar.ma2.DataType SEQUENCE;
public static final ucar.ma2.DataType STRING;
public static final ucar.ma2.DataType STRUCTURE;
public static final ucar.ma2.DataType ENUM1; // byte
public static final ucar.ma2.DataType ENUM2; // short
public static final ucar.ma2.DataType ENUM3; // int
public static final ucar.ma2.DataType OPAQUE; // byte blobs
public static final ucar.ma2.DataType OBJECT;
public static final ucar.ma2.DataType UBYTE;
public static final ucar.ma2.DataType USHORT;
public static final ucar.ma2.DataType UINT;
public static final ucar.ma2.DataType ULONG;
}