All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nom.tam.util.BufferedDataInputStream Maven / Gradle / Ivy

package nom.tam.util;

import static nom.tam.util.LoggerHelper.getLogger;

/*
 * #%L
 * nom.tam FITS library
 * %%
 * Copyright (C) 2004 - 2015 nom-tam-fits
 * %%
 * This is free and unencumbered software released into the public domain.
 * 
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 * 
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS 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.
 * #L%
 */

// What do we use in here?
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class is intended for high performance I/O in scientific applications.
 * It combines the functionality of the BufferedInputStream and the
 * DataInputStream as well as more efficient handling of arrays. This minimizes
 * the number of method calls that are required to read data. Informal tests of
 * this method show that it can be as much as 10 times faster than using a
 * DataInputStream layered on a BufferedInputStream for writing large arrays.
 * The performance gain on scalars or small arrays will be less but there should
 * probably never be substantial degradation of performance.
 * 

* Many new read calls are added to allow efficient reading off array data. The * read(Object o) call provides for reading a primitive array of arbitrary type * or dimensionality. There are also reads for each type of one dimensional * array. *

* Note that there is substantial duplication of code to minimize method * invocations. E.g., the floating point read routines read the data as integer * values and then convert to float. However the integer code is duplicated * rather than invoked. There has been considerable effort expended to ensure * that these routines are efficient, but they could easily be superceded if an * efficient underlying I/O package were ever delivered as part of the basic * Java libraries. [This has subsequently happened with the NIO package and in * an ideal universe these classes would be rewritten to take advantage of NIO.] *

* Testing and timing routines are provided in the * nom.tam.util.test.BufferedFileTester class. Version 1.1: October 12, 2000: * Fixed handling of EOF to return partially read arrays when EOF is detected. * Version 1.2: July 20, 2009: Added handling of very large Object arrays. * Additional work is required to handle very large arrays generally. */ public class BufferedDataInputStream extends BufferedInputStream implements ArrayDataInput { private static final Logger LOG = getLogger(BufferedDataInputStream.class); /** * size of the skip buffer (if it exists) {@link #skipBuf}. */ private static final int SKIP_BUFFER_SIZE = 8192; private final BufferPointer sharedBuffer = new BufferPointer().init(FitsIO.BYTES_IN_LONG); private final BufferDecoder bufferDecoder = new BufferDecoder(this.sharedBuffer) { @Override protected void checkBuffer(int needBytes) throws IOException { if (needBytes > 0) { readBytesIntoSharedBuffer(needBytes); } } @Override protected int eofCheck(EOFException e, int start, int index, int length) throws EOFException { return BufferedDataInputStream.this.eofCheck(e, index, start, length); } @Override protected int read(byte[] buf, int offset, int length) throws IOException { return BufferedDataInputStream.this.read(buf, offset, length); } }; /** * Skip the requested number of bytes. This differs from the skip call in * that it takes an long argument and will throw an end of file if the full * number of bytes cannot be skipped. * * @param toSkip * The number of bytes to skip. */ private byte[] skipBuf = null; /** * Create a BufferedInputStream based on an input stream. * * @param o * the input stream to use for reading. */ public BufferedDataInputStream(InputStream o) { this(o, FitsIO.DEFAULT_BUFFER_SIZE); } /** * Create a BufferedInputStream based on a input stream with a specified * buffer size. * * @param o * the input stream to use for reading. * @param bufLength * the buffer length to use. */ public BufferedDataInputStream(InputStream o, int bufLength) { super(o, bufLength); } /** * For array reads return an EOF if unable to read any data. * * @param e * the eof exception that happened. * @param i * the current index * @param start * the start index * @param length * the element length * @return the number of bytes read before the end of file exception. * @throws EOFException * if no extra bytes could be read */ private int eofCheck(EOFException e, int i, int start, int length) throws EOFException { if (i == start) { throw e; } else { return (i - start) * length; } } @Override public int read(boolean[] b) throws IOException { return read(b, 0, b.length); } @Override public int read(boolean[] b, int start, int length) throws IOException { return this.bufferDecoder.read(b, start, length); } @Override public int read(byte[] obuf, int offset, int length) throws IOException { int total = 0; int remainingToRead = length; int currentOffset = offset; while (remainingToRead > 0) { // Use just the buffered I/O to get needed info. int xlen = super.read(obuf, currentOffset, remainingToRead); if (xlen <= 0) { if (total == 0) { throw new EOFException(); } else { return total; } } else { remainingToRead -= xlen; total += xlen; currentOffset += xlen; } } return total; } @Override public int read(char[] c) throws IOException { return read(c, 0, c.length); } @Override public int read(char[] c, int start, int length) throws IOException { return this.bufferDecoder.read(c, start, length); } @Override public int read(double[] d) throws IOException { return read(d, 0, d.length); } @Override public int read(double[] d, int start, int length) throws IOException { return this.bufferDecoder.read(d, start, length); } @Override public int read(float[] f) throws IOException { return read(f, 0, f.length); } @Override public int read(float[] f, int start, int length) throws IOException { return this.bufferDecoder.read(f, start, length); } @Override public int read(int[] i) throws IOException { return read(i, 0, i.length); } @Override public int read(int[] i, int start, int length) throws IOException { return this.bufferDecoder.read(i, start, length); } @Override public int read(long[] l) throws IOException { return read(l, 0, l.length); } @Override public int read(long[] l, int start, int length) throws IOException { return this.bufferDecoder.read(l, start, length); } @Override public int read(short[] s) throws IOException { return read(s, 0, s.length); } @Override public int read(short[] s, int start, int length) throws IOException { return this.bufferDecoder.read(s, start, length); } @Deprecated @Override public int readArray(Object o) throws IOException { return (int) readLArray(o); } @Override public boolean readBoolean() throws IOException { return read() == 1; } @Override public byte readByte() throws IOException { return (byte) read(); } private void readBytesIntoSharedBuffer(int bytes) throws IOException, EOFException { this.sharedBuffer.invalidate(); if (read(this.sharedBuffer.buffer, 0, bytes) < bytes) { throw new EOFException(); } } @Override public char readChar() throws IOException { return this.bufferDecoder.readChar(); } @Override public double readDouble() throws IOException { return this.bufferDecoder.readDouble(); } @Override public float readFloat() throws IOException { return this.bufferDecoder.readFloat(); } @Override public void readFully(byte[] b) throws IOException { this.bufferDecoder.readFully(b, 0, b.length); } @Override public void readFully(byte[] b, int off, int len) throws IOException { this.bufferDecoder.readFully(b, off, len); } @Override public int readInt() throws IOException { return this.bufferDecoder.readInt(); } @Override public long readLArray(Object o) throws IOException { return this.bufferDecoder.readLArray(o); } /** * Emulate the deprecated DataInputStream.readLine() method. Originally we * used the method itself, but Alan Brighton suggested using a * java.io.BufferedReader to eliminate the deprecation warning. This was * used for a long time, but more recently we noted that this doesn't work. * We now use a simple method that largely ignores character encodings and * only uses the "\n" as the line separator. This method is slow regardless. * In the current version * * @return The String read. * @deprecated Use {@link java.io.BufferedReader} methods. */ @Deprecated @Override public String readLine() throws IOException { // Punt on this and use BufferedReader routines. StringBuilder b = new StringBuilder(0); int chr; while ((chr = read()) >= 0) { if (chr != '\n') { b.append((char) chr); } else { return b.toString(); } } return b.toString(); } @Override public long readLong() throws IOException { return this.bufferDecoder.readLong(); } /** * This routine provides efficient reading of arrays of any primitive type. * It is an error to invoke this method with an object that is not an array * of some primitive type. Note that there is no corresponding capability to * writePrimitiveArray in BufferedDataOutputStream to read in an array of * Strings. * * @return number of bytes read. * @param o * The object to be read. It must be an array of a primitive * type, or an array of Object's. * @throws IOException * if the underlying read operation fails * @deprecated use {@link #readLArray(Object)} instead */ @Deprecated public int readPrimitiveArray(Object o) throws IOException { return (int) readLArray(o); } @Override public short readShort() throws IOException { return this.bufferDecoder.readShort(); } @Override public int readUnsignedByte() throws IOException { return read() & FitsIO.BYTE_MASK; } @Override public int readUnsignedShort() throws IOException { return this.bufferDecoder.readShort() & FitsIO.SHORT_MASK; } @Override public String readUTF() throws IOException { return DataInputStream.readUTF(this); } @Override public void skipAllBytes(int toSkip) throws IOException { skipAllBytes((long) toSkip); } @Override public void skipAllBytes(long toSkip) throws IOException { long need = toSkip; while (need > 0) { try { long got = skip(need); if (got > 0) { need -= got; } else { break; } } catch (IOException e) { long lastNeed = need; need = handleExceptionInSkip(need, e); if (need >= lastNeed) { break; } } } if (need > 0) { throw new EOFException(); } } private long handleExceptionInSkip(long skip, IOException e) throws IOException { LOG.log(Level.WARNING, "Error while skipping bytes", e); // Some input streams (process outputs) don't allow // skipping. The kludgy solution here is to // try to do a read when we get an error in the skip.... // Real IO errors will presumably cause an error // in these reads too. if (this.skipBuf == null) { this.skipBuf = new byte[BufferedDataInputStream.SKIP_BUFFER_SIZE]; } long remainingToSkip = skip; while (remainingToSkip > BufferedDataInputStream.SKIP_BUFFER_SIZE) { int got = read(this.skipBuf, 0, BufferedDataInputStream.SKIP_BUFFER_SIZE); if (got <= 0) { break; } remainingToSkip -= got; } while (remainingToSkip > 0) { int got = read(this.skipBuf, 0, (int) remainingToSkip); if (got <= 0) { break; } remainingToSkip -= got; } return remainingToSkip; } @Override public int skipBytes(int toSkip) throws IOException { skipAllBytes(toSkip); return toSkip; } @Override public String toString() { return super.toString() + "[count=" + this.count + ",pos=" + this.pos + "]"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy