org.h2gis.functions.io.utility.ReadBufferManager Maven / Gradle / Ivy
/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* . H2GIS is developed by CNRS
* .
*
* This code is part of the H2GIS project. H2GIS is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation;
* version 3.0 of the License.
*
* H2GIS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details .
*
*
* For more information, please consult:
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.io.utility;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
public final class ReadBufferManager {
private int bufferSize;
private ByteBuffer buffer;
private FileChannel channel;
private long windowStart;
private long positionInFile;
/**
* Instantiates a ReadBufferManager to read the specified channel
*
* @param channel
* @throws java.io.IOException
*/
public ReadBufferManager(FileChannel channel) throws IOException {
this(channel, 1024 * 32);
}
/**
* Instantiates a ReadBufferManager to read the specified channel. The
* specified bufferSize is the size of the channel content cached in memory
*
* @param channel
* @param bufferSize
* @throws java.io.IOException
*/
public ReadBufferManager(FileChannel channel, int bufferSize)
throws IOException {
this.channel = channel;
buffer = ByteBuffer.allocate(0);
windowStart = 0;
this.bufferSize = bufferSize;
getWindowOffset(0, bufferSize);
}
/**
* Moves the window if necessary to contain the desired byte and returns the
* position of the byte in the window
*
* @param bytePos
* @throws java.io.IOException
*/
private int getWindowOffset(long bytePos, int length) throws IOException {
long desiredMin = bytePos;
long desiredMax = desiredMin + length - 1;
if ((desiredMin >= windowStart)
&& (desiredMax < windowStart + buffer.capacity())) {
long res = desiredMin - windowStart;
if (res < Integer.MAX_VALUE) {
return (int) res;
} else {
throw new IOException("this buffer is quite large...");
}
} else {
long bufferCapacity = Math.max(bufferSize, length);
long size = channel.size();
bufferCapacity = Math.min(bufferCapacity, size - bytePos);
if (bufferCapacity > Integer.MAX_VALUE) {
throw new IOException("Woaw ! You want to have a REALLY LARGE buffer !");
}
windowStart = bytePos;
channel.position(windowStart);
if (buffer.capacity() != bufferCapacity) {
ByteOrder order = buffer.order();
buffer = ByteBuffer.allocate((int)bufferCapacity);
buffer.order(order);
} else {
buffer.clear();
}
channel.read(buffer);
buffer.flip();
return (int) (desiredMin - windowStart);
}
}
/**
* Gets the byte value at the specified position
*
* @param bytePos
* @return
* @throws java.io.IOException
*/
public byte getByte(long bytePos) throws IOException {
int windowOffset = getWindowOffset(bytePos, 1);
return buffer.get(windowOffset);
}
/**
* Gets the size of the channel
*
* @return
* @throws java.io.IOException
*/
public long getLength() throws IOException {
return channel.size();
}
/**
* Specifies the byte order. One of the constants in {@link java.nio.ByteBuffer}
*
* @param order
*/
public void order(ByteOrder order) {
buffer.order(order);
}
/**
* Gets the int value at the specified position
*
* @param bytePos
* @return
* @throws java.io.IOException
*/
public int getInt(long bytePos) throws IOException {
int windowOffset = getWindowOffset(bytePos, 4);
return buffer.getInt(windowOffset);
}
/**
* Gets the long value at the specified position
*
* @param bytePos
* @return
* @throws java.io.IOException
*/
public long getLong(long bytePos) throws IOException {
int windowOffset = getWindowOffset(bytePos, 8);
return buffer.getLong(windowOffset);
}
/**
* Gets the long value at the current position
*
* @param bytePos
* @return
* @throws java.io.IOException
*/
public long getLong() throws IOException {
long ret = getLong(positionInFile);
positionInFile += 8;
return ret;
}
/**
* Gets the byte value at the current position
*
* @return
* @throws java.io.IOException
*/
public byte get() throws IOException {
byte ret = getByte(positionInFile);
positionInFile += 1;
return ret;
}
/**
* Gets the int value at the current position
*
* @return
* @throws java.io.IOException
*/
public int getInt() throws IOException {
int ret = getInt(positionInFile);
positionInFile += 4;
return ret;
}
/**
* skips the specified number of bytes from the current position in the
* channel
*
* @param numBytes
* @throws java.io.IOException
*/
public void skip(int numBytes) throws IOException {
positionInFile += numBytes;
}
/**
* Gets the byte[] value at the current position
*
* @param buffer
* @return
* @throws java.io.IOException
*/
public ByteBuffer get(byte[] buffer) throws IOException {
int windowOffset = getWindowOffset(positionInFile, buffer.length);
this.buffer.position(windowOffset);
positionInFile += buffer.length;
return this.buffer.get(buffer);
}
/**
* Gets the byte[] value at the specified position
*
* @param pos
* @param buffer
* @return
* @throws java.io.IOException
*/
public ByteBuffer get(long pos, byte[] buffer) throws IOException {
int windowOffset = getWindowOffset(pos, buffer.length);
this.buffer.position(windowOffset);
return this.buffer.get(buffer);
}
/**
* Moves the current position to the specified one
*
* @param position
*/
public void position(long position) {
this.positionInFile = position;
}
/**
* Gets the positionf of this buffer in the file it's reading.
*
* @return
*/
public long getPosition() {
return positionInFile;
}
/**
* Gets the double value at the specified position
*
* @return
* @throws java.io.IOException
*/
public double getDouble() throws IOException {
double ret = getDouble(positionInFile);
positionInFile += 8;
return ret;
}
/**
* Gets the double value at the specified position
*
* @param bytePos
* @return
* @throws java.io.IOException
*/
public double getDouble(long bytePos) throws IOException {
int windowOffset = getWindowOffset(bytePos, 8);
return buffer.getDouble(windowOffset);
}
/**
* If the current position is at the end of the channel
*
* @return
* @throws java.io.IOException
*/
public boolean isEOF() throws IOException {
return (buffer.remaining() == 0)
&& (windowStart + buffer.capacity() >= channel.size());
}
/**
* Gets the number of remaining bytes in the current file, starting from the
* current position
*
* @return a number of bytes >=0
* @throws java.io.IOException
*/
public long remaining() throws IOException {
return channel.size() - windowStart - buffer.position();
}
}