diff options
Diffstat (limited to 'src/mscorlib/src/System/IO/StreamWriter.cs')
-rw-r--r-- | src/mscorlib/src/System/IO/StreamWriter.cs | 175 |
1 files changed, 37 insertions, 138 deletions
diff --git a/src/mscorlib/src/System/IO/StreamWriter.cs b/src/mscorlib/src/System/IO/StreamWriter.cs index 65613bb0a6..22eba82605 100644 --- a/src/mscorlib/src/System/IO/StreamWriter.cs +++ b/src/mscorlib/src/System/IO/StreamWriter.cs @@ -2,25 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** -** -** Purpose: For writing text to streams in a particular -** encoding. -** -** -===========================================================*/ -using System; using System.Text; -using System.Threading; -using System.Globalization; using System.Runtime.CompilerServices; -using System.Runtime.Versioning; using System.Security.Permissions; using System.Runtime.Serialization; +using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Threading.Tasks; @@ -45,10 +31,8 @@ namespace System.IO private const int DefaultFileStreamBufferSize = 4096; private const int MinBufferSize = 128; - private const Int32 DontCopyOnWriteLineThreshold = 512; - // Bit bucket - Null has no backing store. Non closable. - public new static readonly StreamWriter Null = new StreamWriter(Stream.Null, new UTF8Encoding(false, true), MinBufferSize, true); + public new static readonly StreamWriter Null = new StreamWriter(Stream.Null, UTF8NoBOM, MinBufferSize, true); private Stream stream; private Encoding encoding; @@ -61,12 +45,6 @@ namespace System.IO private bool haveWrittenPreamble; private bool closable; -#if MDA_SUPPORTED - [NonSerialized] - // For StreamWriterBufferedDataLost MDA - private MdaHelper mdaHelper; -#endif - // 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. @@ -93,20 +71,9 @@ namespace System.IO // 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! - private static volatile Encoding _UTF8NoBOM; - internal static Encoding UTF8NoBOM { [FriendAccessAllowed] - get { - if (_UTF8NoBOM == null) { - // No need for double lock - we just want to avoid extra - // allocations in the common case. - UTF8Encoding noBOM = new UTF8Encoding(false, true); - Thread.MemoryBarrier(); - _UTF8NoBOM = noBOM; - } - return _UTF8NoBOM; - } + get { return EncodingCache.UTF8NoBOM; } } @@ -133,10 +100,10 @@ namespace System.IO : base(null) // Ask for CurrentCulture all the time { if (stream == null || encoding == null) - throw new ArgumentNullException((stream == null ? "stream" : "encoding")); + 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("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); + if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize), Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); Contract.EndContractBlock(); Init(stream, encoding, bufferSize, leaveOpen); @@ -154,28 +121,23 @@ namespace System.IO : this(path, append, encoding, DefaultBufferSize) { } - [System.Security.SecuritySafeCritical] - public StreamWriter(String path, bool append, Encoding encoding, int bufferSize): this(path, append, encoding, bufferSize, true) { - } - - [System.Security.SecurityCritical] - internal StreamWriter(String path, bool append, Encoding encoding, int bufferSize, bool checkHost) + public StreamWriter(String path, bool append, Encoding encoding, int bufferSize) : base(null) - { // Ask for CurrentCulture all the time + { + // Ask for CurrentCulture all the time if (path == null) - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); if (encoding == null) - throw new ArgumentNullException("encoding"); + throw new ArgumentNullException(nameof(encoding)); if (path.Length == 0) throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath")); - if (bufferSize <= 0) throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); + if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize), Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); Contract.EndContractBlock(); - Stream stream = CreateFile(path, append, checkHost); + Stream stream = CreateFile(path, append); Init(stream, encoding, bufferSize, false); } - [System.Security.SecuritySafeCritical] private void Init(Stream streamArg, Encoding encodingArg, int bufferSize, bool shouldLeaveOpen) { this.stream = streamArg; @@ -190,21 +152,12 @@ namespace System.IO if (stream.CanSeek && stream.Position > 0) haveWrittenPreamble = true; closable = !shouldLeaveOpen; -#if MDA_SUPPORTED - if (Mda.StreamWriterBufferedDataLost.Enabled) { - String callstack = null; - if (Mda.StreamWriterBufferedDataLost.CaptureAllocatedCallStack) - callstack = Environment.GetStackTrace(null, false); - mdaHelper = new MdaHelper(this, callstack); - } -#endif } - [System.Security.SecurityCritical] - private static Stream CreateFile(String path, bool append, bool checkHost) { + 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, checkHost); + DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false); return f; } @@ -221,20 +174,11 @@ namespace System.IO // is generally the right thing to do. if (stream != null) { // Note: flush on the underlying stream can throw (ex., low disk space) -#if FEATURE_CORECLR if (disposing) -#else - if (disposing || (LeaveOpen && stream is __ConsoleStream)) -#endif { CheckAsyncTaskInProgress(); Flush(true, true); -#if MDA_SUPPORTED - // Disable buffered data loss mda - if (mdaHelper != null) - GC.SuppressFinalize(mdaHelper); -#endif } } } @@ -354,7 +298,7 @@ namespace System.IO if (charPos == charLen) Flush(false, false); int n = charLen - charPos; if (n > count) n = count; - Contract.Assert(n > 0, "StreamWriter::Write(char[]) isn't making progress! This is most likely a race condition in user code."); + 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; @@ -365,11 +309,11 @@ namespace System.IO public override void Write(char[] buffer, int index, int count) { if (buffer==null) - throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer")); + throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) - throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (buffer.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); Contract.EndContractBlock(); @@ -380,7 +324,7 @@ namespace System.IO if (charPos == charLen) Flush(false, false); int n = charLen - charPos; if (n > count) n = count; - Contract.Assert(n > 0, "StreamWriter::Write(char[], int, int) isn't making progress! This is most likely a race condition in user code."); + 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; @@ -402,7 +346,7 @@ namespace System.IO if (charPos == charLen) Flush(false, false); int n = charLen - charPos; if (n > count) n = count; - Contract.Assert(n > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code."); + 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; @@ -413,7 +357,6 @@ namespace System.IO } #region Task based Async APIs - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteAsync(char value) { @@ -444,7 +387,7 @@ namespace System.IO { if (charPos == charLen) { await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } @@ -457,7 +400,7 @@ namespace System.IO { if (charPos == charLen) { await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } @@ -468,14 +411,13 @@ namespace System.IO if (autoFlush) { await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } _this.CharPos_Prop = charPos; } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteAsync(String value) { @@ -520,7 +462,7 @@ namespace System.IO { if (charPos == charLen) { await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } @@ -528,7 +470,7 @@ namespace System.IO if (n > count) n = count; - Contract.Assert(n > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code."); + 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); @@ -543,7 +485,7 @@ namespace System.IO { if (charPos == charLen) { await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } @@ -554,23 +496,22 @@ namespace System.IO if (autoFlush) { await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } _this.CharPos_Prop = charPos; } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteAsync(char[] buffer, int index, int count) { if (buffer==null) - throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer")); + throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) - throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (buffer.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); Contract.EndContractBlock(); @@ -609,14 +550,14 @@ namespace System.IO { if (charPos == charLen) { await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } int n = charLen - charPos; if (n > count) n = count; - Contract.Assert(n > 0, "StreamWriter::Write(char[], int, int) isn't making progress! This is most likely a race condition in user code."); + 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)); @@ -631,7 +572,7 @@ namespace System.IO { if (charPos == charLen) { await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } @@ -642,14 +583,13 @@ namespace System.IO if (autoFlush) { await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false); - Contract.Assert(_this.charPos == 0); + Debug.Assert(_this.charPos == 0); charPos = 0; } _this.CharPos_Prop = charPos; } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteLineAsync() { @@ -672,7 +612,6 @@ namespace System.IO } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteLineAsync(char value) { @@ -695,7 +634,6 @@ namespace System.IO } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteLineAsync(String value) { @@ -718,16 +656,15 @@ namespace System.IO } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task WriteLineAsync(char[] buffer, int index, int count) { if (buffer==null) - throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer")); + throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) - throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (buffer.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); Contract.EndContractBlock(); @@ -751,7 +688,6 @@ namespace System.IO } - [HostProtection(ExternalThreading = true)] [ComVisible(false)] public override Task FlushAsync() { @@ -825,42 +761,5 @@ namespace System.IO await stream.FlushAsync().ConfigureAwait(false); } #endregion - -#if MDA_SUPPORTED - // StreamWriterBufferedDataLost MDA - // Instead of adding a finalizer to StreamWriter for detecting buffered data loss - // (ie, when the user forgets to call Close/Flush on the StreamWriter), we will - // have a separate object with normal finalization semantics that maintains a - // back pointer to this StreamWriter and alerts about any data loss - private sealed class MdaHelper - { - private StreamWriter streamWriter; - private String allocatedCallstack; // captures the callstack when this streamwriter was allocated - - internal MdaHelper(StreamWriter sw, String cs) - { - streamWriter = sw; - allocatedCallstack = cs; - } - - // Finalizer - ~MdaHelper() - { - // Make sure people closed this StreamWriter, exclude StreamWriter::Null. - if (streamWriter.charPos != 0 && streamWriter.stream != null && streamWriter.stream != Stream.Null) { - String fileName = (streamWriter.stream is FileStream) ? ((FileStream)streamWriter.stream).NameInternal : "<unknown>"; - String callStack = allocatedCallstack; - - if (callStack == null) - callStack = Environment.GetResourceString("IO_StreamWriterBufferedDataLostCaptureAllocatedFromCallstackNotEnabled"); - - String message = Environment.GetResourceString("IO_StreamWriterBufferedDataLost", streamWriter.stream.GetType().FullName, fileName, callStack); - - Mda.StreamWriterBufferedDataLost.ReportError(message); - } - } - } // class MdaHelper -#endif // MDA_SUPPORTED - } // class StreamWriter } // namespace |