/// <summary> /// Reads data from the stream. /// </summary> /// <param name="buffer">The buffer to fill</param> /// <param name="offset">The first byte in buffer to fill</param> /// <param name="count">The requested number of bytes to read</param> /// <returns>The actual number of bytes read</returns> public override int Read(byte[] buffer, int offset, int count) { lock (_common) { SparseStream wrapped = Wrapped; wrapped.Position = _position; int numRead = wrapped.Read(buffer, offset, count); _position += numRead; return(numRead); } }
public override int Read(byte[] buffer, int offset, int count) { return(_wrapped.Read(buffer, offset, count)); }
internal override int Read(long diskOffset, byte[] block, int offset, int count) { _stream.Position = diskOffset - Start; return(_stream.Read(block, offset, count)); }
/// <summary> /// Reads data from the stream. /// </summary> /// <param name="buffer">The buffer to fill</param> /// <param name="offset">The buffer offset to start from</param> /// <param name="count">The number of bytes to read</param> /// <returns>The number of bytes read</returns> public override int Read(byte[] buffer, int offset, int count) { CheckDisposed(); if (_position >= Length) { if (_atEof) { throw new IOException("Attempt to read beyond end of stream"); } else { _atEof = true; return(0); } } _stats.TotalReadsIn++; if (count > _settings.LargeReadSize) { _stats.LargeReadsIn++; _stats.TotalReadsOut++; _wrappedStream.Position = _position; int numRead = _wrappedStream.Read(buffer, offset, count); _position = _wrappedStream.Position; if (_position >= Length) { _atEof = true; } return(numRead); } int totalBytesRead = 0; bool servicedFromCache = false; bool servicedOutsideCache = false; int blockSize = _settings.BlockSize; long firstBlock = _position / blockSize; int offsetInNextBlock = (int)(_position % blockSize); long endBlock = Utilities.Ceil(Math.Min(_position + count, Length), blockSize); int numBlocks = (int)(endBlock - firstBlock); if (offsetInNextBlock != 0) { _stats.UnalignedReadsIn++; } int blocksRead = 0; while (blocksRead < numBlocks) { Block block; // Read from the cache as much as possible while (blocksRead < numBlocks && _cache.TryGetBlock(firstBlock + blocksRead, out block)) { int bytesToRead = Math.Min(count - totalBytesRead, block.Available - offsetInNextBlock); Array.Copy(block.Data, offsetInNextBlock, buffer, offset + totalBytesRead, bytesToRead); offsetInNextBlock = 0; totalBytesRead += bytesToRead; _position += bytesToRead; blocksRead++; servicedFromCache = true; } // Now handle a sequence of (one or more) blocks that are not cached if (blocksRead < numBlocks && !_cache.ContainsBlock(firstBlock + blocksRead)) { servicedOutsideCache = true; // Figure out how many blocks to read from the wrapped stream int blocksToRead = 0; while (blocksRead + blocksToRead < numBlocks && blocksToRead < _blocksInReadBuffer && !_cache.ContainsBlock(firstBlock + blocksRead + blocksToRead)) { ++blocksToRead; } // Allow for the end of the stream not being block-aligned long readPosition = (firstBlock + blocksRead) * (long)blockSize; int bytesToRead = (int)Math.Min(blocksToRead * (long)blockSize, Length - readPosition); // Do the read _stats.TotalReadsOut++; _wrappedStream.Position = readPosition; int bytesRead = Utilities.ReadFully(_wrappedStream, _readBuffer, 0, bytesToRead); if (bytesRead != bytesToRead) { throw new IOException("Short read before end of stream"); } // Cache the read blocks for (int i = 0; i < blocksToRead; ++i) { int copyBytes = Math.Min(blockSize, bytesToRead - (i * blockSize)); block = _cache.GetBlock(firstBlock + blocksRead + i); Array.Copy(_readBuffer, i * blockSize, block.Data, 0, copyBytes); block.Available = copyBytes; if (copyBytes < blockSize) { Array.Clear(_readBuffer, (i * blockSize) + copyBytes, blockSize - copyBytes); } } blocksRead += blocksToRead; // Propogate the data onto the caller int bytesToCopy = Math.Min(count - totalBytesRead, bytesRead - offsetInNextBlock); Array.Copy(_readBuffer, offsetInNextBlock, buffer, offset + totalBytesRead, bytesToCopy); totalBytesRead += bytesToCopy; _position += bytesToCopy; offsetInNextBlock = 0; } } if (_position >= Length && totalBytesRead == 0) { _atEof = true; } if (servicedFromCache) { _stats.ReadCacheHits++; } if (servicedOutsideCache) { _stats.ReadCacheMisses++; } return(totalBytesRead); }
/// <summary> /// Reads from the buffer into a byte array. /// </summary> /// <param name="pos">The offset within the buffer to start reading.</param> /// <param name="buffer">The destination byte array.</param> /// <param name="offset">The start offset within the destination buffer.</param> /// <param name="count">The number of bytes to read.</param> /// <returns>The actual number of bytes read</returns> public override int Read(long pos, byte[] buffer, int offset, int count) { _stream.Position = pos; return(_stream.Read(buffer, offset, count)); }