@Override
    public long skip(final long n) throws IOException {
        // The first seek we do we check the index
        if (!checkedIndex) {
            // Record the current position in case we don't switch blocks
            final long originalPos = raFile.position();
            final BlockBufferedInputStream originalRawBuffer = currentRawStreamBuffer;
            raFile.position(idxStart);
            // Must create a new buffer as we switch back the old one
            currentRawStreamBuffer = createBufferedInputStream(false);
            readMagicMarker();
            checkedIndex = true;
            // Move Back
            raFile.position(originalPos);
            // Switch back the old one
            currentRawStreamBuffer = originalRawBuffer;
        }

        final long currentBlockNumber = position / blockSize;

        // Find the new offset in the file.
        position = position + n;

        if (position > dataLength) {
            throw new IOException("Seek past EOF");
        }
        if (position < 0) {
            throw new IOException("Seek past begining of file");
        }

        // Then figure out block and offset
        final long newBlockNumber = position / blockSize;
        final long newBlockOffset = position % blockSize;

        // Moving block?
        if ((currentBlockNumber != newBlockNumber)) {
            // Read our index
            raFile.position(idxStart
                    + BlockGZIPConstants.LONG_BYTES
                    + (newBlockNumber * BlockGZIPConstants.LONG_BYTES));
            currentRawStreamBuffer = createBufferedInputStream(true);
            final long seekPos = readLong();
            raFile.position(seekPos);
            currentRawStreamBuffer = createBufferedInputStream(true);
            startGzipBlock();
            currentStream.skip(newBlockOffset);
        } else {
            // Start a BGZIP block
            if (currentStream == null) {
                startGzipBlock();
            }

            // Still in the same block
            currentStream.skip(n);
        }

        // We always can do the full skip
        return n;
    }
Here we provide random access into a stream.
stroom-data/stroom-data-store-impl-fs/src/main/java/stroom/data/store/impl/fs/BlockGZIPInputFile.java