public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { 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 /*, no good single parameter name to pass*/); } if (GetType() != typeof(FileStream)) { // If we have been inherited into a subclass, the following implementation could be incorrect // since it does not call through to Write() or WriteAsync() which a subclass might have overridden. // To be safe we will only use this implementation in cases where we know it is safe to do so, // and delegate to our base class (which will call into Write/WriteAsync) when we are not sure. return(base.WriteAsync(buffer, offset, count, cancellationToken)); } if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } if (IsClosed) { throw Error.GetFileNotOpen(); } if (!_useAsyncIO) { // If we weren't opened for asynchronous I/O, we still call to the base implementation so that // Write is invoked asynchronously. But we can do so using the base Stream's internal helper // that bypasses delegating to BeginWrite, since we already know this is FileStream rather // than something derived from it and what our BeginWrite implementation is going to do. return((Task)base.BeginWriteInternal(buffer, offset, count, null, null, serializeAsynchronously: true, apm: false)); } return(WriteAsyncInternal(new ReadOnlyMemory <byte>(buffer, offset, count), cancellationToken).AsTask()); }
public override int Read(Span <byte> buffer) { if (!_useAsyncIO) { if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } return(ReadSpan(buffer)); } // If the stream is in async mode, we can't call the synchronous ReadSpan, so we similarly call the base Read, // which will turn delegate to Read(byte[],int,int), which will do the right thing if we're in async mode. return(base.Read(buffer)); }
public virtual byte ReadByte() { // Inlined to avoid some method call overhead with FillBuffer. if (_stream == null) { throw Error.GetFileNotOpen(); } int b = _stream.ReadByte(); if (b == -1) { throw Error.GetEndOfFile(); } return((byte)b); }
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ValidateBufferArguments(buffer, offset, count); if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } if (_strategy.IsClosed) { throw Error.GetFileNotOpen(); } return(_strategy.WriteAsync(buffer, offset, count, cancellationToken)); }
public virtual int PeekChar() { if (_stream == null) { throw Error.GetFileNotOpen(); } if (!_stream.CanSeek) { return(-1); } long origPos = _stream.Position; int ch = Read(); _stream.Position = origPos; return(ch); }
private byte InternalReadByte() { // Inlined to avoid some method call overhead with InternalRead. if (_stream == null) { throw Error.GetFileNotOpen(); } int b = _stream.ReadByte(); if (b == -1) { throw Error.GetEndOfFile(); } return((byte)b); }
public override void Write(ReadOnlySpan <byte> buffer) { if (!_useAsyncIO) { if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } WriteSpan(buffer); } else { // If the stream is in async mode, we can't call the synchronous WriteSpan, so we similarly call the base Write, // which will turn delegate to Write(byte[],int,int), which will do the right thing if we're in async mode. base.Write(buffer); } }
public override Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { 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 /*, no good single parameter name to pass*/); } // If we have been inherited into a subclass, the following implementation could be incorrect // since it does not call through to Read() which a subclass might have overridden. // To be safe we will only use this implementation in cases where we know it is safe to do so, // and delegate to our base class (which will call into Read/ReadAsync) when we are not sure. // Similarly, if we weren't opened for asynchronous I/O, call to the base implementation so that // Read is invoked asynchronously. if (GetType() != typeof(FileStream) || !_useAsyncIO) { return(base.ReadAsync(buffer, offset, count, cancellationToken)); } if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled <int>(cancellationToken)); } if (IsClosed) { throw Error.GetFileNotOpen(); } return(ReadAsyncTask(buffer, offset, count, cancellationToken)); }
/// <summary> /// Validates that we're ready to write to the stream, /// including flushing a read buffer if necessary. /// </summary> private void PrepareForWriting() { if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } // Make sure we're good to write. We only need to do this if there's nothing already // in our write buffer, since if there is something in the buffer, we've already done // this checking and flushing. if (_writePos == 0) { if (!CanWrite) { throw Error.GetWriteNotSupported(); } FlushReadBuffer(); Debug.Assert(_bufferLength > 0, "_bufferSize > 0"); } }
public virtual int ReadInt32() { if (_isMemoryStream) { if (_stream == null) { throw Error.GetFileNotOpen(); } // read directly from MemoryStream buffer MemoryStream mStream = _stream as MemoryStream; Debug.Assert(mStream != null, "_stream as MemoryStream != null"); return(mStream.InternalReadInt32()); } else { FillBuffer(4); return((int)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24)); } }
public virtual byte[] ReadBytes(int count) { if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); } if (_stream == null) { throw Error.GetFileNotOpen(); } if (count == 0) { return(Array.Empty <Byte>()); } byte[] result = new byte[count]; int numRead = 0; do { int n = _stream.Read(result, numRead, count); if (n == 0) { break; } numRead += n; count -= n; } while (count > 0); if (numRead != result.Length) { // Trim array. This should happen on EOF & possibly net streams. byte[] copy = new byte[numRead]; Buffer.BlockCopy(result, 0, copy, 0, numRead); result = copy; } return(result); }
/// <summary>Sets the length of this stream to the given value.</summary> /// <param name="value">The new length of the stream.</param> public override void SetLength(long value) { if (value < 0) { throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_NeedNonNegNum); } if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } if (!CanSeek) { throw Error.GetSeekNotSupported(); } if (!CanWrite) { throw Error.GetWriteNotSupported(); } SetLengthInternal(value); }
public override int Read(Span <byte> destination) { if (GetType() == typeof(FileStream) && !_useAsyncIO) { if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } return(ReadSpan(destination)); } else { // This type is derived from FileStream and/or the stream is in async mode. If this is a // derived type, it may have overridden Read(byte[], int, int) prior to this Read(Span<byte>) // overload being introduced. In that case, this Read(Span<byte>) overload should use the behavior // of Read(byte[],int,int) overload. Or if the stream is in async mode, we can't call the // synchronous ReadSpan, so we similarly call the base Read, which will turn delegate to // Read(byte[],int,int), which will do the right thing if we're in async mode. return(base.Read(destination)); } }
public override void Write(ReadOnlySpan <byte> buffer) { if (GetType() == typeof(FileStream) && !_useAsyncIO) { if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } WriteSpan(buffer); } else { // This type is derived from FileStream and/or the stream is in async mode. If this is a // derived type, it may have overridden Write(byte[], int, int) prior to this Write(ReadOnlySpan<byte>) // overload being introduced. In that case, this Write(ReadOnlySpan<byte>) overload should use the behavior // of Write(byte[],int,int) overload. Or if the stream is in async mode, we can't call the // synchronous WriteSpan, so we similarly call the base Write, which will turn delegate to // Write(byte[],int,int), which will do the right thing if we're in async mode. base.Write(buffer); } }
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { 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 /*, no good single parameter name to pass*/); } // If we have been inherited into a subclass, the following implementation could be incorrect // since it does not call through to Write() or WriteAsync() which a subclass might have overridden. // To be safe we will only use this implementation in cases where we know it is safe to do so, // and delegate to our base class (which will call into Write/WriteAsync) when we are not sure. if (!_useAsyncIO || GetType() != typeof(FileStream)) { return(base.WriteAsync(buffer, offset, count, cancellationToken)); } if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } if (IsClosed) { throw Error.GetFileNotOpen(); } return(WriteAsyncInternal(new ReadOnlyMemory <byte>(buffer, offset, count), cancellationToken).AsTask()); }
protected virtual void FillBuffer(int numBytes) { if (_buffer != null && (numBytes < 0 || numBytes > _buffer.Length)) { throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_BinaryReaderFillBuffer); } int bytesRead = 0; int n = 0; if (_stream == null) { throw Error.GetFileNotOpen(); } // Need to find a good threshold for calling ReadByte() repeatedly // vs. calling Read(byte[], int, int) for both buffered & unbuffered // streams. if (numBytes == 1) { n = _stream.ReadByte(); if (n == -1) { throw Error.GetEndOfFile(); } _buffer[0] = (byte)n; return; } do { n = _stream.Read(_buffer, bytesRead, numBytes - bytesRead); if (n == 0) { throw Error.GetEndOfFile(); } bytesRead += n; } while (bytesRead < numBytes); }
public override ValueTask WriteAsync(ReadOnlyMemory <byte> buffer, CancellationToken cancellationToken = default) { if (!_useAsyncIO || GetType() != typeof(FileStream)) { // If we're not using async I/O, delegate to the base, which will queue a call to Write. // Or if this isn't a concrete FileStream, a derived type may have overridden WriteAsync(byte[],...), // which was introduced first, so delegate to the base which will delegate to that. return(base.WriteAsync(buffer, cancellationToken)); } if (cancellationToken.IsCancellationRequested) { return(new ValueTask(Task.FromCanceled <int>(cancellationToken))); } if (IsClosed) { throw Error.GetFileNotOpen(); } return(WriteAsyncInternal(buffer, cancellationToken)); }
/// <summary> /// Asynchronously writes a sequence of bytes to the current stream, advances /// the current position within this stream by the number of bytes written, and /// monitors cancellation requests. /// </summary> /// <param name="source">The buffer to write data from.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>A task that represents the asynchronous write operation.</returns> private ValueTask WriteAsyncInternal(ReadOnlyMemory <byte> source, CancellationToken cancellationToken) { Debug.Assert(_useAsyncIO); Debug.Assert(_asyncState != null); if (cancellationToken.IsCancellationRequested) { return(new ValueTask(Task.FromCanceled(cancellationToken))); } if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } if (!CanWrite) // match Windows behavior; this gets thrown synchronously { throw Error.GetWriteNotSupported(); } // Serialize operations using the semaphore. Task waitTask = _asyncState.WaitAsync(); // If we got ownership immediately, and if there's enough space in our buffer // to buffer the entire write request, then do so and we're done. if (waitTask.Status == TaskStatus.RanToCompletion) { int spaceRemaining = _bufferLength - _writePos; if (spaceRemaining >= source.Length) { try { PrepareForWriting(); source.Span.CopyTo(new Span <byte>(GetBuffer(), _writePos, source.Length)); _writePos += source.Length; return(default);
/// <summary>Validates arguments to Read and Write and throws resulting exceptions.</summary> /// <param name="array">The buffer to read from or write to.</param> /// <param name="offset">The zero-based offset into the array.</param> /// <param name="count">The maximum number of bytes to read or write.</param> private void ValidateReadWriteArgs(byte[] array, int offset, int count) { if (array == null) { throw new ArgumentNullException(nameof(array), 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 (array.Length - offset < count) { throw new ArgumentException(SR.Argument_InvalidOffLen /*, no good single parameter name to pass*/); } if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } }
/// <summary>Asynchronously clears all buffers for this stream, causing any buffered data to be written to the underlying device.</summary> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>A task that represents the asynchronous flush operation.</returns> private Task FlushAsyncInternal(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } // As with Win32FileStream, flush the buffers synchronously to avoid race conditions. try { FlushInternalBuffer(); } catch (Exception e) { return(Task.FromException(e)); } // We then separately flush to disk asynchronously. This is only // necessary if we support writing; otherwise, we're done. if (CanWrite) { return(Task.Factory.StartNew( state => ((FileStream)state).FlushOSBuffer(), this, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); } else { return(Task.CompletedTask); } }
public override ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken = default) { if (GetType() != typeof(FileStream)) { // If this isn't a concrete FileStream, a derived type may have overridden ReadAsync(byte[],...), // which was introduced first, so delegate to the base which will delegate to that. return(base.ReadAsync(buffer, cancellationToken)); } if (cancellationToken.IsCancellationRequested) { return(new ValueTask <int>(Task.FromCanceled <int>(cancellationToken))); } if (IsClosed) { throw Error.GetFileNotOpen(); } if (!_useAsyncIO) { // If we weren't opened for asynchronous I/O, we still call to the base implementation so that // Read is invoked asynchronously. But if we have a byte[], we can do so using the base Stream's // internal helper that bypasses delegating to BeginRead, since we already know this is FileStream // rather than something derived from it and what our BeginRead implementation is going to do. return(MemoryMarshal.TryGetArray(buffer, out ArraySegment <byte> segment) ? new ValueTask <int>((Task <int>)base.BeginReadInternal(segment.Array !, segment.Offset, segment.Count, null, null, serializeAsynchronously: true, apm: false)) : base.ReadAsync(buffer, cancellationToken)); } Task <int>?t = ReadAsyncInternal(buffer, cancellationToken, out int synchronousResult); return(t != null ? new ValueTask <int>(t) : new ValueTask <int>(synchronousResult)); }
/// <summary> /// Asynchronously writes a sequence of bytes to the current stream, advances /// the current position within this stream by the number of bytes written, and /// monitors cancellation requests. /// </summary> /// <param name="source">The buffer to write data from.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>A task that represents the asynchronous write operation.</returns> private Task WriteAsyncInternal(ReadOnlyMemory <byte> source, CancellationToken cancellationToken) { Debug.Assert(_useAsyncIO); if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } if (_fileHandle.IsClosed) { throw Error.GetFileNotOpen(); } if (!CanWrite) // match Windows behavior; this gets thrown synchronously { throw Error.GetWriteNotSupported(); } // Serialize operations using the semaphore. Task waitTask = _asyncState.WaitAsync(); // If we got ownership immediately, and if there's enough space in our buffer // to buffer the entire write request, then do so and we're done. if (waitTask.Status == TaskStatus.RanToCompletion) { int spaceRemaining = _bufferLength - _writePos; if (spaceRemaining >= source.Length) { try { PrepareForWriting(); source.Span.CopyTo(new Span <byte>(GetBuffer(), _writePos, source.Length)); _writePos += source.Length; return(Task.CompletedTask); } catch (Exception exc) { return(Task.FromException(exc)); } finally { _asyncState.Release(); } } } // Otherwise, issue the whole request asynchronously. _asyncState.ReadOnlyMemory = source; 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 { ReadOnlyMemory <byte> readOnlyMemory = thisRef._asyncState.ReadOnlyMemory; thisRef._asyncState.ReadOnlyMemory = default(ReadOnlyMemory <byte>); thisRef.WriteSpan(readOnlyMemory.Span); } finally { thisRef._asyncState.Release(); } }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default)); }
public virtual int Read() { if (_stream == null) { throw Error.GetFileNotOpen(); } int charsRead = 0; int numBytes = 0; long posSav = posSav = 0; if (_stream.CanSeek) { posSav = _stream.Position; } if (_charBytes == null) { _charBytes = new byte[MaxCharBytesSize]; //REVIEW: We need at most 2 bytes/char here? } if (_singleChar == null) { _singleChar = new char[1]; } while (charsRead == 0) { // We really want to know what the minimum number of bytes per char // is for our encoding. Otherwise for UnicodeEncoding we'd have to // do ~1+log(n) reads to read n characters. // Assume 1 byte can be 1 char unless _2BytesPerChar is true. numBytes = _2BytesPerChar ? 2 : 1; int r = _stream.ReadByte(); _charBytes[0] = (byte)r; if (r == -1) { numBytes = 0; } if (numBytes == 2) { r = _stream.ReadByte(); _charBytes[1] = (byte)r; if (r == -1) { numBytes = 1; } } if (numBytes == 0) { return(-1); } Debug.Assert(numBytes == 1 || numBytes == 2, "BinaryReader::ReadOneChar assumes it's reading one or 2 bytes only."); try { charsRead = _decoder.GetChars(_charBytes, 0, numBytes, _singleChar, 0); } catch { // Handle surrogate char if (_stream.CanSeek) { _stream.Seek((posSav - _stream.Position), SeekOrigin.Current); } // else - we can't do much here throw; } Debug.Assert(charsRead < 2, "BinaryReader::ReadOneChar - assuming we only got 0 or 1 char, not 2!"); } Debug.Assert(charsRead > 0); return(_singleChar[0]); }
public virtual string ReadString() { if (_stream == null) { throw Error.GetFileNotOpen(); } int currPos = 0; int n; int stringLength; int readLength; int charsRead; // Length of the string in bytes, not chars stringLength = Read7BitEncodedInt(); if (stringLength < 0) { throw new IOException(SR.Format(SR.IO_InvalidStringLen_Len, stringLength)); } if (stringLength == 0) { return(string.Empty); } if (_charBytes == null) { _charBytes = new byte[MaxCharBytesSize]; } if (_charBuffer == null) { _charBuffer = new char[_maxCharsSize]; } StringBuilder sb = null; do { readLength = ((stringLength - currPos) > MaxCharBytesSize) ? MaxCharBytesSize : (stringLength - currPos); n = _stream.Read(_charBytes, 0, readLength); if (n == 0) { throw Error.GetEndOfFile(); } charsRead = _decoder.GetChars(_charBytes, 0, n, _charBuffer, 0); if (currPos == 0 && n == stringLength) { return(new string(_charBuffer, 0, charsRead)); } if (sb == null) { sb = StringBuilderCache.Acquire(stringLength); // Actual string length in chars may be smaller. } sb.Append(_charBuffer, 0, charsRead); currPos += n; } while (currPos < stringLength); return(StringBuilderCache.GetStringAndRelease(sb)); }