public void ViewIO() { SparseMemoryStream memStream = new SparseMemoryStream(); memStream.SetLength(1024); ThreadSafeStream tss = new ThreadSafeStream(memStream); SparseStream altView = tss.OpenView(); // Check positions are independant tss.Position = 100; Assert.AreEqual(0, altView.Position); Assert.AreEqual(100, tss.Position); // Check I/O is synchronous byte[] buffer = new byte[200]; tss.WriteByte(99); altView.Read(buffer, 0, 200); Assert.AreEqual(99, buffer[100]); // Check positions are updated correctly Assert.AreEqual(200, altView.Position); Assert.AreEqual(101, tss.Position); }
/// <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); } }
/// <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)); }
/// <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"); } _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) * 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); }
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)); }