private void checkAndAdvanceBlockInStream() throws IOException { if (mCurrentBlockLeft == 0) { if (mCurrentBlockInStream != null) { mCurrentBlockInStream.close(); } mCurrentBlockIndex = getCurrentBlockIndex(); mCurrentBlockInStream = BlockInStream.get(FILE, READ_TYPE, mCurrentBlockIndex); mCurrentBlockLeft = BLOCK_CAPACITY; } }
@Override public int read(byte[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int tOff = off; int tLen = len; while (tLen > 0 && mCurrentPosition < FILE_LENGTH) { checkAndAdvanceBlockInStream(); int tRead = mCurrentBlockInStream.read(b, tOff, tLen); mCurrentPosition += tRead; mCurrentBlockLeft -= tRead; tLen -= tRead; tOff += tRead; } return len - tLen; }
/** * Return the {@code InStream} of this file based on the specified read type. If it has no block, * return an {@code EmptyBlockInStream}; if it has only one block, return a {@code BlockInStream} * of the block; otherwise return a {@code FileInStream}. * * @param readType the InStream's read type * @return the InStream * @throws IOException */ public InStream getInStream(ReadType readType) throws IOException { if (readType == null) { throw new IOException("ReadType can not be null."); } if (!isComplete()) { throw new IOException("The file " + this + " is not complete."); } if (isDirectory()) { throw new IOException("Cannot open a directory for reading."); } ClientFileInfo fileStatus = getUnCachedFileStatus(); List<Long> blocks = fileStatus.getBlockIds(); if (blocks.size() == 0) { return new EmptyBlockInStream(this, readType, mTachyonConf); } if (blocks.size() == 1) { return BlockInStream.get(this, readType, 0, mUFSConf, mTachyonConf); } return new FileInStream(this, readType, mUFSConf, mTachyonConf); }
@Override public void close() throws IOException { if (!mClosed && mCurrentBlockInStream != null) { mCurrentBlockInStream.close(); } mClosed = true; }
@Override public void seek(long pos) throws IOException { if (mCurrentPosition == pos) { return; } if (pos < 0) { throw new IOException("pos is negative: " + pos); } if ((int) (pos / BLOCK_CAPACITY) != mCurrentBlockIndex) { mCurrentBlockIndex = (int) (pos / BLOCK_CAPACITY); if (mCurrentBlockInStream != null) { mCurrentBlockInStream.close(); } mCurrentBlockInStream = BlockInStream.get(FILE, READ_TYPE, mCurrentBlockIndex); } mCurrentBlockInStream.seek(pos % BLOCK_CAPACITY); mCurrentPosition = pos; mCurrentBlockLeft = BLOCK_CAPACITY - (pos % BLOCK_CAPACITY); }
@Override public int read() throws IOException { if (mCurrentPosition >= FILE_LENGTH) { return -1; } checkAndAdvanceBlockInStream(); mCurrentPosition++; mCurrentBlockLeft--; return mCurrentBlockInStream.read(); }
@Override public long skip(long n) throws IOException { if (n <= 0) { return 0; } long ret = n; if (mCurrentPosition + n >= FILE.length()) { ret = FILE.length() - mCurrentPosition; mCurrentPosition += ret; } else { mCurrentPosition += n; } int tBlockIndex = (int) (mCurrentPosition / BLOCK_CAPACITY); if (tBlockIndex != mCurrentBlockIndex) { if (mCurrentBlockInStream != null) { mCurrentBlockInStream.close(); } mCurrentBlockIndex = tBlockIndex; mCurrentBlockInStream = BlockInStream.get(FILE, READ_TYPE, mCurrentBlockIndex); long shouldSkip = mCurrentPosition % BLOCK_CAPACITY; long skip = mCurrentBlockInStream.skip(shouldSkip); mCurrentBlockLeft = BLOCK_CAPACITY - skip; if (skip != shouldSkip) { throw new IOException( "The underlayer BlockInStream only skip " + skip + " instead of " + shouldSkip); } } else { long skip = mCurrentBlockInStream.skip(ret); if (skip != ret) { throw new IOException( "The underlayer BlockInStream only skip " + skip + " instead of " + ret); } } return ret; }