BinaryIO.java
package gov.usgs.earthquake.product.io;
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Date;
public class BinaryIO {
/**
* Writes an int to the OutputStream buffer
* @param in an int to write
* @param out the OutputStream
* @throws IOException if IO error occurs
*/
public void writeInt(final int in, final OutputStream out)
throws IOException {
out.write(ByteBuffer.allocate(4).putInt(in).array());
}
/**
* Writes an long to the OutputStream buffer
* @param in an long to write
* @param out the OutputStream
* @throws IOException if IO error occurs
*/
public void writeLong(final long in, final OutputStream out)
throws IOException {
out.write(ByteBuffer.allocate(8).putLong(in).array());
}
/**
* Writes an array of bytes to the OutputStream buffer
* @param toWrite an array of bytes to write
* @param out the OutputStream
* @throws IOException if IO error occurs
*/
public void writeBytes(final byte[] toWrite, final OutputStream out)
throws IOException {
// length of string
writeInt(toWrite.length, out);
// string
out.write(toWrite);
}
/**
* Writes a string to the OutputStream buffer
* @param toWrite a string to write
* @param out the OutputStream
* @throws IOException if IO error occurs
*/
public void writeString(final String toWrite, final OutputStream out)
throws IOException {
writeBytes(toWrite.getBytes(StandardCharsets.UTF_8), out);
}
/**
* Writes a date to the OutputStream buffer
* @param toWrite a date to write
* @param out the OutputStream
* @throws IOException if IO error occurs
*/
public void writeDate(final Date toWrite, final OutputStream out)
throws IOException {
writeLong(toWrite.getTime(), out);
}
/**
* Writes a long to the OutputStream buffer
* @param length a long to write
* @param in an input stream
* @param out the OutputStream
* @throws IOException if IO error occurs
*/
public void writeStream(final long length, final InputStream in,
final OutputStream out) throws IOException {
writeLong(length, out);
// transfer stream bytes
int read = -1;
byte[] bytes = new byte[1024];
// read no more than length bytes
while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
}
/**
* Reads 4 bytes from the InputStream
* @param in InputStream
* @return an int
* @throws IOException if IO Error occurs
*/
public int readInt(final InputStream in) throws IOException {
byte[] buffer = new byte[4];
readFully(buffer, in);
return ByteBuffer.wrap(buffer).getInt();
}
/**
* Reads 8 bytes from the InputStream
* @param in InputStream
* @return a long
* @throws IOException if IO Error occurs
*/
public long readLong(final InputStream in) throws IOException {
byte[] buffer = new byte[8];
readFully(buffer, in);
return ByteBuffer.wrap(buffer).getLong();
}
/**
* Reads a byte array from the InputStream
* @param in InputStream
* @return Byte[]
* @throws IOException if IO Error occurs
*/
public byte[] readBytes(final InputStream in) throws IOException {
int length = readInt(in);
byte[] buffer = new byte[length];
readFully(buffer, in);
return buffer;
}
/**
* Reads string from the InputStream
* @param in InputStream
* @return a string
* @throws IOException if IO Error occurs
*/
public String readString(final InputStream in) throws IOException {
return this.readString(in, -1);
}
/**
* Reads string with a max length from the InputStream
* @param in InputStream
* @param maxLength of string
* @return an string
* @throws IOException if IO Error occurs
*/
public String readString(final InputStream in, final int maxLength) throws IOException {
int length = readInt(in);
if (maxLength > 0 && length > maxLength) {
throw new IOException("request string length " + length + " greater than maxLength " + maxLength);
}
byte[] buffer = new byte[length];
readFully(buffer, in);
return new String(buffer, StandardCharsets.UTF_8);
}
/**
* Reads date from the InputStream
* @param in InputStream
* @return a date
* @throws IOException if IO Error occurs
*/
public Date readDate(final InputStream in) throws IOException {
return new Date(readLong(in));
}
/**
* Reads stream
* @param in InputStream
* @param out OutputStream
* @throws IOException if IO Error occurs
*/
public void readStream(final InputStream in, final OutputStream out)
throws IOException {
long length = readLong(in);
readStream(length, in, out);
}
/**
* Function called by previous readStream
* Used to read whole stream
* @param length length of inputstream
* @param in input stream
* @param out output stream
* @throws IOException if io error occurs
*/
public void readStream(final long length, final InputStream in,
final OutputStream out) throws IOException {
long remaining = length;
// transfer stream bytes, not going over total
int read = -1;
byte[] bytes = new byte[1024];
int readSize = bytes.length;
while (remaining > 0) {
if (remaining < readSize) {
// don't read past end of stream
readSize = (int) remaining;
}
// read next chunk
read = in.read(bytes, 0, readSize);
if (read == -1) {
// shouldn't be at eof, since reading length specified in stream
throw new EOFException();
}
// track how much has been read
remaining -= read;
// transfer to out stream
out.write(bytes, 0, read);
}
}
/**
* Function used by other read funcs
* Reads from input stream until buffer is full
* @param buffer byte[]
* @param in inputstream
* @throws IOException if IO error occurs
*/
protected void readFully(final byte[] buffer, final InputStream in)
throws IOException {
int length = buffer.length;
int totalRead = 0;
int read = -1;
while ((read = in.read(buffer, totalRead, length - totalRead)) != -1) {
totalRead += read;
if (totalRead == length) {
break;
}
}
if (totalRead != length) {
throw new IOException("EOF before buffer could be readFully, read=" + totalRead + ", expected=" + length);
}
}
}