package org.epics.archiverappliance.utils.nio;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
/**
* Compressed files typically do not let us seek arbitrarily within the stream.
* This is a inefficient workaround for this.
* This can be improved with ZRan like functionality later if needed.
* This implements a read only seekable byte channel over a one way input stream.
* @author mshankar
*
*/
public class WrappedSeekableByteChannel implements SeekableByteChannel {
private Path srcPath = null;
private InputStream backingIs = null;
long position = 0;
public WrappedSeekableByteChannel(Path path) throws IOException {
this.srcPath = path;
backingIs = Files.newInputStream(srcPath, StandardOpenOption.READ);
}
@Override
public void close() throws IOException {
if( backingIs != null) backingIs.close();
backingIs = null;
}
@Override
public boolean isOpen() {
return backingIs != null;
}
@Override
public long position() throws IOException {
return position;
}
@Override
public SeekableByteChannel position(long newPosition) throws IOException {
if(newPosition == position) {
// No need to do anything...
} else if(newPosition > position) {
backingIs.skip(newPosition - position);
this.position = newPosition;
} else {
// Here's the inefficient part, we close the stream and open another
backingIs.close();
backingIs = null;
backingIs = Files.newInputStream(srcPath, StandardOpenOption.READ);
backingIs.skip(newPosition);
this.position = newPosition;
}
return this;
}
@Override
public int read(ByteBuffer byteBuf) throws IOException {
int bufPotential = byteBuf.remaining();
byte[] buf = new byte[bufPotential];
int bytesRead = backingIs.read(buf);
if(bytesRead > 0) {
byteBuf.put(buf, 0, bytesRead);
position = position + bytesRead;
return bytesRead;
}
return -1;
}
@Override
public long size() throws IOException {
return Files.size(srcPath);
}
@Override
public SeekableByteChannel truncate(long arg0) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int write(ByteBuffer arg0) throws IOException {
throw new UnsupportedOperationException();
}
}