protected void ValidateRead(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0 || count < 0) { throw new ArgumentOutOfRangeException((offset < 0 ? "offset" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum); } if (buffer.Length - offset < count) { throw new ArgumentException(SR.Argument_InvalidOffLen); } Contract.EndContractBlock(); if (!_canRead) { throw Error.GetReadNotSupported(); } }
/// <summary> /// Asynchronously reads a sequence of bytes from the current stream and advances /// the position within the stream by the number of bytes read. /// </summary> /// <param name="destination">The buffer to write the data into.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="synchronousResult">If the operation completes synchronously, the number of bytes read.</param> /// <returns>A task that represents the asynchronous read operation.</returns> private Task <int> ReadAsyncInternal(Memory <byte> destination, CancellationToken cancellationToken, out int synchronousResult) { Debug.Assert(_useAsyncIO); if (!CanRead) // match Windows behavior; this gets thrown synchronously { throw Error.GetReadNotSupported(); } // Serialize operations using the semaphore. Task waitTask = _asyncState.WaitAsync(); // If we got ownership immediately, and if there's enough data in our buffer // to satisfy the full request of the caller, hand back the buffered data. // While it would be a legal implementation of the Read contract, we don't // hand back here less than the amount requested so as to match the behavior // in ReadCore that will make a native call to try to fulfill the remainder // of the request. if (waitTask.Status == TaskStatus.RanToCompletion) { int numBytesAvailable = _readLength - _readPos; if (numBytesAvailable >= destination.Length) { try { PrepareForReading(); new Span <byte>(GetBuffer(), _readPos, destination.Length).CopyTo(destination.Span); _readPos += destination.Length; synchronousResult = destination.Length; return(null); } catch (Exception exc) { synchronousResult = 0; return(Task.FromException <int>(exc)); } finally { _asyncState.Release(); } } } // Otherwise, issue the whole request asynchronously. synchronousResult = 0; _asyncState.Memory = destination; return(waitTask.ContinueWith((t, s) => { // The options available on Unix for writing asynchronously to an arbitrary file // handle typically amount to just using another thread to do the synchronous write, // which is exactly what this implementation does. This does mean there are subtle // differences in certain FileStream behaviors between Windows and Unix when multiple // asynchronous operations are issued against the stream to execute concurrently; on // Unix the operations will be serialized due to the usage of a semaphore, but the // position /length information won't be updated until after the write has completed, // whereas on Windows it may happen before the write has completed. Debug.Assert(t.Status == TaskStatus.RanToCompletion); var thisRef = (FileStream)s; try { Memory <byte> memory = thisRef._asyncState.Memory; thisRef._asyncState.Memory = default(Memory <byte>); return thisRef.ReadSpan(memory.Span); } finally { thisRef._asyncState.Release(); } }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default)); }
/// <summary> /// Reads bytes from stream and puts them into the buffer /// </summary> /// <param name="buffer">Buffer to read the bytes to.</param> /// <param name="offset">Starting index in the buffer.</param> /// <param name="count">Maximum number of bytes to read.</param> /// <returns>Number of bytes actually read.</returns> public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); } if (buffer.Length - offset < count) { throw new ArgumentException(SR.Argument_InvalidOffLen); } Contract.EndContractBlock(); // Keep this in sync with contract validation in ReadAsync if (!_isOpen) { throw Error.GetStreamIsClosed(); } if (!CanRead) { throw Error.GetReadNotSupported(); } // Use a local variable to avoid a race where another thread // changes our position after we decide we can read some bytes. long pos = Interlocked.Read(ref _position); long len = Interlocked.Read(ref _length); long n = len - pos; if (n > count) { n = count; } if (n <= 0) { return(0); } int nInt = (int)n; // Safe because n <= count, which is an Int32 if (nInt < 0) { return(0); // _position could be beyond EOF } Debug.Assert(pos + nInt >= 0, "_position + n >= 0"); // len is less than 2^63 -1. unsafe { fixed(byte *pBuffer = buffer) { if (_buffer != null) { byte *pointer = null; RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); Buffer.Memcpy(pBuffer + offset, pointer + pos + _offset, nInt); } finally { if (pointer != null) { _buffer.ReleasePointer(); } } } else { Buffer.Memcpy(pBuffer + offset, _mem + pos, nInt); } } } Interlocked.Exchange(ref _position, pos + n); return(nInt); }
public override int Read(Span <byte> buffer) => throw Error.GetReadNotSupported();
internal int ReadCore(Span <byte> destination) { if (!_isOpen) { throw Error.GetStreamIsClosed(); } if (!CanRead) { throw Error.GetReadNotSupported(); } // Use a local variable to avoid a race where another thread // changes our position after we decide we can read some bytes. long pos = Interlocked.Read(ref _position); long len = Interlocked.Read(ref _length); long n = Math.Min(len - pos, destination.Length); if (n <= 0) { return(0); } int nInt = (int)n; // Safe because n <= count, which is an Int32 if (nInt < 0) { return(0); // _position could be beyond EOF } Debug.Assert(pos + nInt >= 0, "_position + n >= 0"); // len is less than 2^63 -1. unsafe { fixed(byte *pBuffer = &destination.DangerousGetPinnableReference()) { if (_buffer != null) { byte *pointer = null; RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); Buffer.Memcpy(pBuffer, pointer + pos + _offset, nInt); } finally { if (pointer != null) { _buffer.ReleasePointer(); } } } else { Buffer.Memcpy(pBuffer, _mem + pos, nInt); } } } Interlocked.Exchange(ref _position, pos + n); return(nInt); }