summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/IO/StreamWriter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/IO/StreamWriter.cs')
-rw-r--r--src/mscorlib/src/System/IO/StreamWriter.cs765
1 files changed, 0 insertions, 765 deletions
diff --git a/src/mscorlib/src/System/IO/StreamWriter.cs b/src/mscorlib/src/System/IO/StreamWriter.cs
deleted file mode 100644
index 22eba82..0000000
--- a/src/mscorlib/src/System/IO/StreamWriter.cs
+++ /dev/null
@@ -1,765 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Text;
-using System.Runtime.CompilerServices;
-using System.Security.Permissions;
-using System.Runtime.Serialization;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-
-namespace System.IO
-{
- // This class implements a TextWriter for writing characters to a Stream.
- // This is designed for character output in a particular Encoding,
- // whereas the Stream class is designed for byte input and output.
- //
- [Serializable]
- [ComVisible(true)]
- public class StreamWriter : TextWriter
- {
- // For UTF-8, the values of 1K for the default buffer size and 4K for the
- // file stream buffer size are reasonable & give very reasonable
- // performance for in terms of construction time for the StreamWriter and
- // write perf. Note that for UTF-8, we end up allocating a 4K byte buffer,
- // which means we take advantage of adaptive buffering code.
- // The performance using UnicodeEncoding is acceptable.
- internal const int DefaultBufferSize = 1024; // char[]
- private const int DefaultFileStreamBufferSize = 4096;
- private const int MinBufferSize = 128;
-
- // Bit bucket - Null has no backing store. Non closable.
- public new static readonly StreamWriter Null = new StreamWriter(Stream.Null, UTF8NoBOM, MinBufferSize, true);
-
- private Stream stream;
- private Encoding encoding;
- private Encoder encoder;
- private byte[] byteBuffer;
- private char[] charBuffer;
- private int charPos;
- private int charLen;
- private bool autoFlush;
- private bool haveWrittenPreamble;
- private bool closable;
-
- // We don't guarantee thread safety on StreamWriter, but we should at
- // least prevent users from trying to write anything while an Async
- // write from the same thread is in progress.
- [NonSerialized]
- private volatile Task _asyncWriteTask;
-
- private void CheckAsyncTaskInProgress()
- {
- // We are not locking the access to _asyncWriteTask because this is not meant to guarantee thread safety.
- // We are simply trying to deter calling any Write APIs while an async Write from the same thread is in progress.
-
- Task t = _asyncWriteTask;
-
- if (t != null && !t.IsCompleted)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncIOInProgress"));
- }
-
- // The high level goal is to be tolerant of encoding errors when we read and very strict
- // when we write. Hence, default StreamWriter encoding will throw on encoding error.
- // Note: when StreamWriter throws on invalid encoding chars (for ex, high surrogate character
- // D800-DBFF without a following low surrogate character DC00-DFFF), it will cause the
- // internal StreamWriter's state to be irrecoverable as it would have buffered the
- // illegal chars and any subsequent call to Flush() would hit the encoding error again.
- // Even Close() will hit the exception as it would try to flush the unwritten data.
- // Maybe we can add a DiscardBufferedData() method to get out of such situation (like
- // StreamReader though for different reason). Either way, the buffered data will be lost!
- internal static Encoding UTF8NoBOM {
- [FriendAccessAllowed]
- get { return EncodingCache.UTF8NoBOM; }
- }
-
-
- internal StreamWriter(): base(null) { // Ask for CurrentCulture all the time
- }
-
- public StreamWriter(Stream stream)
- : this(stream, UTF8NoBOM, DefaultBufferSize, false) {
- }
-
- public StreamWriter(Stream stream, Encoding encoding)
- : this(stream, encoding, DefaultBufferSize, false) {
- }
-
- // Creates a new StreamWriter for the given stream. The
- // character encoding is set by encoding and the buffer size,
- // in number of 16-bit characters, is set by bufferSize.
- //
- public StreamWriter(Stream stream, Encoding encoding, int bufferSize)
- : this(stream, encoding, bufferSize, false) {
- }
-
- public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
- : base(null) // Ask for CurrentCulture all the time
- {
- if (stream == null || encoding == null)
- throw new ArgumentNullException((stream == null ? nameof(stream) : nameof(encoding)));
- if (!stream.CanWrite)
- throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
- if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize), Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
- Contract.EndContractBlock();
-
- Init(stream, encoding, bufferSize, leaveOpen);
- }
-
- public StreamWriter(String path)
- : this(path, false, UTF8NoBOM, DefaultBufferSize) {
- }
-
- public StreamWriter(String path, bool append)
- : this(path, append, UTF8NoBOM, DefaultBufferSize) {
- }
-
- public StreamWriter(String path, bool append, Encoding encoding)
- : this(path, append, encoding, DefaultBufferSize) {
- }
-
- public StreamWriter(String path, bool append, Encoding encoding, int bufferSize)
- : base(null)
- {
- // Ask for CurrentCulture all the time
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (encoding == null)
- throw new ArgumentNullException(nameof(encoding));
- if (path.Length == 0)
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
- if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize), Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
- Contract.EndContractBlock();
-
- Stream stream = CreateFile(path, append);
- Init(stream, encoding, bufferSize, false);
- }
-
- private void Init(Stream streamArg, Encoding encodingArg, int bufferSize, bool shouldLeaveOpen)
- {
- this.stream = streamArg;
- this.encoding = encodingArg;
- this.encoder = encoding.GetEncoder();
- if (bufferSize < MinBufferSize) bufferSize = MinBufferSize;
- charBuffer = new char[bufferSize];
- byteBuffer = new byte[encoding.GetMaxByteCount(bufferSize)];
- charLen = bufferSize;
- // If we're appending to a Stream that already has data, don't write
- // the preamble.
- if (stream.CanSeek && stream.Position > 0)
- haveWrittenPreamble = true;
- closable = !shouldLeaveOpen;
- }
-
- private static Stream CreateFile(String path, bool append) {
- FileMode mode = append? FileMode.Append: FileMode.Create;
- FileStream f = new FileStream(path, mode, FileAccess.Write, FileShare.Read,
- DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false);
- return f;
- }
-
- public override void Close() {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected override void Dispose(bool disposing) {
- try {
- // We need to flush any buffered data if we are being closed/disposed.
- // Also, we never close the handles for stdout & friends. So we can safely
- // write any buffered data to those streams even during finalization, which
- // is generally the right thing to do.
- if (stream != null) {
- // Note: flush on the underlying stream can throw (ex., low disk space)
- if (disposing)
- {
- CheckAsyncTaskInProgress();
-
- Flush(true, true);
- }
- }
- }
- finally {
- // Dispose of our resources if this StreamWriter is closable.
- // Note: Console.Out and other such non closable streamwriters should be left alone
- if (!LeaveOpen && stream != null) {
- try {
- // Attempt to close the stream even if there was an IO error from Flushing.
- // Note that Stream.Close() can potentially throw here (may or may not be
- // due to the same Flush error). In this case, we still need to ensure
- // cleaning up internal resources, hence the finally block.
- if (disposing)
- stream.Close();
- }
- finally {
- stream = null;
- byteBuffer = null;
- charBuffer = null;
- encoding = null;
- encoder = null;
- charLen = 0;
- base.Dispose(disposing);
- }
- }
- }
- }
-
- public override void Flush()
- {
- CheckAsyncTaskInProgress();
-
- Flush(true, true);
- }
-
- private void Flush(bool flushStream, bool flushEncoder)
- {
- // flushEncoder should be true at the end of the file and if
- // the user explicitly calls Flush (though not if AutoFlush is true).
- // This is required to flush any dangling characters from our UTF-7
- // and UTF-8 encoders.
- if (stream == null)
- __Error.WriterClosed();
-
- // Perf boost for Flush on non-dirty writers.
- if (charPos==0 && (!flushStream && !flushEncoder))
- return;
-
- if (!haveWrittenPreamble) {
- haveWrittenPreamble = true;
- byte[] preamble = encoding.GetPreamble();
- if (preamble.Length > 0)
- stream.Write(preamble, 0, preamble.Length);
- }
-
- int count = encoder.GetBytes(charBuffer, 0, charPos, byteBuffer, 0, flushEncoder);
- charPos = 0;
- if (count > 0)
- stream.Write(byteBuffer, 0, count);
- // By definition, calling Flush should flush the stream, but this is
- // only necessary if we passed in true for flushStream. The Web
- // Services guys have some perf tests where flushing needlessly hurts.
- if (flushStream)
- stream.Flush();
- }
-
- public virtual bool AutoFlush {
- get { return autoFlush; }
-
- set
- {
- CheckAsyncTaskInProgress();
-
- autoFlush = value;
- if (value) Flush(true, false);
- }
- }
-
- public virtual Stream BaseStream {
- get { return stream; }
- }
-
- internal bool LeaveOpen {
- get { return !closable; }
- }
-
- internal bool HaveWrittenPreamble {
- set { haveWrittenPreamble= value; }
- }
-
- public override Encoding Encoding {
- get { return encoding; }
- }
-
- public override void Write(char value)
- {
- CheckAsyncTaskInProgress();
-
- if (charPos == charLen) Flush(false, false);
- charBuffer[charPos] = value;
- charPos++;
- if (autoFlush) Flush(true, false);
- }
-
- public override void Write(char[] buffer)
- {
- // This may be faster than the one with the index & count since it
- // has to do less argument checking.
- if (buffer==null)
- return;
-
- CheckAsyncTaskInProgress();
-
- int index = 0;
- int count = buffer.Length;
- while (count > 0) {
- if (charPos == charLen) Flush(false, false);
- int n = charLen - charPos;
- if (n > count) n = count;
- Debug.Assert(n > 0, "StreamWriter::Write(char[]) isn't making progress! This is most likely a race condition in user code.");
- Buffer.InternalBlockCopy(buffer, index * sizeof(char), charBuffer, charPos * sizeof(char), n * sizeof(char));
- charPos += n;
- index += n;
- count -= n;
- }
- if (autoFlush) Flush(true, false);
- }
-
- public override void Write(char[] buffer, int index, int count) {
- if (buffer==null)
- throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer"));
- if (index < 0)
- throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (count < 0)
- throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (buffer.Length - index < count)
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- Contract.EndContractBlock();
-
- CheckAsyncTaskInProgress();
-
- while (count > 0) {
- if (charPos == charLen) Flush(false, false);
- int n = charLen - charPos;
- if (n > count) n = count;
- Debug.Assert(n > 0, "StreamWriter::Write(char[], int, int) isn't making progress! This is most likely a race condition in user code.");
- Buffer.InternalBlockCopy(buffer, index * sizeof(char), charBuffer, charPos * sizeof(char), n * sizeof(char));
- charPos += n;
- index += n;
- count -= n;
- }
- if (autoFlush) Flush(true, false);
- }
-
- public override void Write(String value)
- {
- if (value != null)
- {
-
- CheckAsyncTaskInProgress();
-
- int count = value.Length;
- int index = 0;
- while (count > 0) {
- if (charPos == charLen) Flush(false, false);
- int n = charLen - charPos;
- if (n > count) n = count;
- Debug.Assert(n > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code.");
- value.CopyTo(index, charBuffer, charPos, n);
- charPos += n;
- index += n;
- count -= n;
- }
- if (autoFlush) Flush(true, false);
- }
- }
-
- #region Task based Async APIs
- [ComVisible(false)]
- public override Task WriteAsync(char value)
- {
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteAsync(value);
-
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, value, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: false);
- _asyncWriteTask = task;
-
- return task;
- }
-
- // We pass in private instance fields of this MarshalByRefObject-derived type as local params
- // to ensure performant access inside the state machine that corresponds this async method.
- // Fields that are written to must be assigned at the end of the method *and* before instance invocations.
- private static async Task WriteAsyncInternal(StreamWriter _this, Char value,
- Char[] charBuffer, Int32 charPos, Int32 charLen, Char[] coreNewLine,
- bool autoFlush, bool appendNewLine)
- {
- if (charPos == charLen) {
- await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- charBuffer[charPos] = value;
- charPos++;
-
- if (appendNewLine)
- {
- for (Int32 i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy
- {
- if (charPos == charLen) {
- await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- charBuffer[charPos] = coreNewLine[i];
- charPos++;
- }
- }
-
- if (autoFlush) {
- await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- _this.CharPos_Prop = charPos;
- }
-
- [ComVisible(false)]
- public override Task WriteAsync(String value)
- {
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteAsync(value);
-
- if (value != null)
- {
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, value, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: false);
- _asyncWriteTask = task;
-
- return task;
- }
- else
- {
- return Task.CompletedTask;
- }
- }
-
- // We pass in private instance fields of this MarshalByRefObject-derived type as local params
- // to ensure performant access inside the state machine that corresponds this async method.
- // Fields that are written to must be assigned at the end of the method *and* before instance invocations.
- private static async Task WriteAsyncInternal(StreamWriter _this, String value,
- Char[] charBuffer, Int32 charPos, Int32 charLen, Char[] coreNewLine,
- bool autoFlush, bool appendNewLine)
- {
- Contract.Requires(value != null);
-
- int count = value.Length;
- int index = 0;
-
- while (count > 0)
- {
- if (charPos == charLen) {
- await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- int n = charLen - charPos;
- if (n > count)
- n = count;
-
- Debug.Assert(n > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code.");
-
- value.CopyTo(index, charBuffer, charPos, n);
-
- charPos += n;
- index += n;
- count -= n;
- }
-
- if (appendNewLine)
- {
- for (Int32 i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy
- {
- if (charPos == charLen) {
- await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- charBuffer[charPos] = coreNewLine[i];
- charPos++;
- }
- }
-
- if (autoFlush) {
- await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- _this.CharPos_Prop = charPos;
- }
-
- [ComVisible(false)]
- public override Task WriteAsync(char[] buffer, int index, int count)
- {
- if (buffer==null)
- throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer"));
- if (index < 0)
- throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (count < 0)
- throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (buffer.Length - index < count)
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- Contract.EndContractBlock();
-
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteAsync(buffer, index, count);
-
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, buffer, index, count, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: false);
- _asyncWriteTask = task;
-
- return task;
- }
-
- // We pass in private instance fields of this MarshalByRefObject-derived type as local params
- // to ensure performant access inside the state machine that corresponds this async method.
- // Fields that are written to must be assigned at the end of the method *and* before instance invocations.
- private static async Task WriteAsyncInternal(StreamWriter _this, Char[] buffer, Int32 index, Int32 count,
- Char[] charBuffer, Int32 charPos, Int32 charLen, Char[] coreNewLine,
- bool autoFlush, bool appendNewLine)
- {
- Contract.Requires(count == 0 || (count > 0 && buffer != null));
- Contract.Requires(index >= 0);
- Contract.Requires(count >= 0);
- Contract.Requires(buffer == null || (buffer != null && buffer.Length - index >= count));
-
- while (count > 0)
- {
- if (charPos == charLen) {
- await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- int n = charLen - charPos;
- if (n > count) n = count;
-
- Debug.Assert(n > 0, "StreamWriter::Write(char[], int, int) isn't making progress! This is most likely a race condition in user code.");
-
- Buffer.InternalBlockCopy(buffer, index * sizeof(char), charBuffer, charPos * sizeof(char), n * sizeof(char));
-
- charPos += n;
- index += n;
- count -= n;
- }
-
- if (appendNewLine)
- {
- for (Int32 i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy
- {
- if (charPos == charLen) {
- await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- charBuffer[charPos] = coreNewLine[i];
- charPos++;
- }
- }
-
- if (autoFlush) {
- await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false);
- Debug.Assert(_this.charPos == 0);
- charPos = 0;
- }
-
- _this.CharPos_Prop = charPos;
- }
-
- [ComVisible(false)]
- public override Task WriteLineAsync()
- {
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteLineAsync();
-
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, null, 0, 0, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: true);
- _asyncWriteTask = task;
-
- return task;
- }
-
-
- [ComVisible(false)]
- public override Task WriteLineAsync(char value)
- {
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteLineAsync(value);
-
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, value, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: true);
- _asyncWriteTask = task;
-
- return task;
- }
-
-
- [ComVisible(false)]
- public override Task WriteLineAsync(String value)
- {
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteLineAsync(value);
-
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, value, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: true);
- _asyncWriteTask = task;
-
- return task;
- }
-
-
- [ComVisible(false)]
- public override Task WriteLineAsync(char[] buffer, int index, int count)
- {
- if (buffer==null)
- throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer"));
- if (index < 0)
- throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (count < 0)
- throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (buffer.Length - index < count)
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- Contract.EndContractBlock();
-
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Write() which a subclass might have overriden.
- // 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) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.WriteLineAsync(buffer, index, count);
-
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = WriteAsyncInternal(this, buffer, index, count, charBuffer, charPos, charLen, CoreNewLine, autoFlush, appendNewLine: true);
- _asyncWriteTask = task;
-
- return task;
- }
-
-
- [ComVisible(false)]
- public override Task FlushAsync()
- {
- // If we have been inherited into a subclass, the following implementation could be incorrect
- // since it does not call through to Flush() which a subclass might have overriden. 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 Flush) when we are not sure.
- if (this.GetType() != typeof(StreamWriter))
- return base.FlushAsync();
-
- // flushEncoder should be true at the end of the file and if
- // the user explicitly calls Flush (though not if AutoFlush is true).
- // This is required to flush any dangling characters from our UTF-7
- // and UTF-8 encoders.
- if (stream == null)
- __Error.WriterClosed();
-
- CheckAsyncTaskInProgress();
-
- Task task = FlushAsyncInternal(true, true, charBuffer, charPos);
- _asyncWriteTask = task;
-
- return task;
- }
-
- private Int32 CharPos_Prop {
- set { this.charPos = value; }
- }
-
- private bool HaveWrittenPreamble_Prop {
- set { this.haveWrittenPreamble = value; }
- }
-
- private Task FlushAsyncInternal(bool flushStream, bool flushEncoder,
- Char[] sCharBuffer, Int32 sCharPos) {
-
- // Perf boost for Flush on non-dirty writers.
- if (sCharPos == 0 && !flushStream && !flushEncoder)
- return Task.CompletedTask;
-
- Task flushTask = FlushAsyncInternal(this, flushStream, flushEncoder, sCharBuffer, sCharPos, this.haveWrittenPreamble,
- this.encoding, this.encoder, this.byteBuffer, this.stream);
-
- this.charPos = 0;
- return flushTask;
- }
-
-
- // We pass in private instance fields of this MarshalByRefObject-derived type as local params
- // to ensure performant access inside the state machine that corresponds this async method.
- private static async Task FlushAsyncInternal(StreamWriter _this, bool flushStream, bool flushEncoder,
- Char[] charBuffer, Int32 charPos, bool haveWrittenPreamble,
- Encoding encoding, Encoder encoder, Byte[] byteBuffer, Stream stream)
- {
- if (!haveWrittenPreamble)
- {
- _this.HaveWrittenPreamble_Prop = true;
- byte[] preamble = encoding.GetPreamble();
- if (preamble.Length > 0)
- await stream.WriteAsync(preamble, 0, preamble.Length).ConfigureAwait(false);
- }
-
- int count = encoder.GetBytes(charBuffer, 0, charPos, byteBuffer, 0, flushEncoder);
- if (count > 0)
- await stream.WriteAsync(byteBuffer, 0, count).ConfigureAwait(false);
-
- // By definition, calling Flush should flush the stream, but this is
- // only necessary if we passed in true for flushStream. The Web
- // Services guys have some perf tests where flushing needlessly hurts.
- if (flushStream)
- await stream.FlushAsync().ConfigureAwait(false);
- }
- #endregion
- } // class StreamWriter
-} // namespace