StreamWriter.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // System.IO.StreamWriter.cs
  3. //
  4. // Author:
  5. // Dietmar Maurer ([email protected])
  6. //
  7. // (C) Ximian, Inc. http://www.ximian.com
  8. //
  9. using System.Text;
  10. using System;
  11. namespace System.IO {
  12. [Serializable]
  13. public class StreamWriter : TextWriter {
  14. private Encoding internalEncoding;
  15. private Stream internalStream;
  16. private bool closed = false;
  17. private bool iflush;
  18. private const int DefaultBufferSize = 1024;
  19. private const int DefaultFileBufferSize = 4096;
  20. private const int MinimumBufferSize = 2;
  21. private int pos;
  22. private int BufferSize;
  23. private byte[] TheBuffer;
  24. private bool DisposedAlready = false;
  25. // new public static readonly StreamWriter Null;
  26. public StreamWriter (Stream stream)
  27. : this (stream, Encoding.UTF8, DefaultBufferSize) {}
  28. public StreamWriter (Stream stream, Encoding encoding)
  29. : this (stream, encoding, DefaultBufferSize) {}
  30. internal void Initialize(Encoding encoding, int bufferSize) {
  31. internalEncoding = encoding;
  32. pos = 0;
  33. BufferSize = Math.Max(bufferSize, MinimumBufferSize);
  34. TheBuffer = new byte[BufferSize];
  35. }
  36. //[MonoTODO("Nothing is done with bufferSize")]
  37. public StreamWriter (Stream stream, Encoding encoding, int bufferSize) {
  38. if (null == stream)
  39. throw new ArgumentNullException("stream");
  40. if (null == encoding)
  41. throw new ArgumentNullException("encoding");
  42. if (bufferSize < 0)
  43. throw new ArgumentOutOfRangeException("bufferSize");
  44. if (!stream.CanWrite)
  45. throw new ArgumentException("bufferSize");
  46. internalStream = stream;
  47. Initialize(encoding, bufferSize);
  48. }
  49. public StreamWriter (string path)
  50. : this (path, false, Encoding.UTF8, DefaultFileBufferSize) {}
  51. public StreamWriter (string path, bool append)
  52. : this (path, append, Encoding.UTF8, DefaultFileBufferSize) {}
  53. public StreamWriter (string path, bool append, Encoding encoding)
  54. : this (path, append, encoding, DefaultFileBufferSize) {}
  55. public StreamWriter (string path, bool append, Encoding encoding, int bufferSize) {
  56. if (null == path)
  57. throw new ArgumentNullException("path");
  58. if (String.Empty == path)
  59. throw new ArgumentException("path cannot be empty string");
  60. if (path.IndexOfAny (Path.InvalidPathChars) != -1)
  61. throw new ArgumentException("path contains invalid characters");
  62. if (null == encoding)
  63. throw new ArgumentNullException("encoding");
  64. if (bufferSize < 0)
  65. throw new ArgumentOutOfRangeException("bufferSize");
  66. string DirName = Path.GetDirectoryName(path);
  67. if (DirName != String.Empty && !Directory.Exists(DirName))
  68. throw new DirectoryNotFoundException();
  69. FileMode mode;
  70. if (append)
  71. mode = FileMode.Append;
  72. else
  73. mode = FileMode.Create;
  74. internalStream = new FileStream (path, mode, FileAccess.Write);
  75. if (append)
  76. internalStream.Position = internalStream.Length;
  77. else
  78. internalStream.SetLength (0);
  79. Initialize(encoding, bufferSize);
  80. }
  81. public virtual bool AutoFlush {
  82. get {
  83. return iflush;
  84. }
  85. set {
  86. iflush = value;
  87. }
  88. }
  89. public virtual Stream BaseStream {
  90. get {
  91. return internalStream;
  92. }
  93. }
  94. public override Encoding Encoding {
  95. get {
  96. return internalEncoding;
  97. }
  98. }
  99. void Dispose() {
  100. Dispose(true);
  101. // Take yourself off of the Finalization queue
  102. // to prevent finalization code for this object
  103. // from executing a second time.
  104. GC.SuppressFinalize(this);
  105. }
  106. protected override void Dispose (bool disposing) {
  107. if (!DisposedAlready && disposing && internalStream != null) {
  108. Flush();
  109. internalStream.Close ();
  110. internalStream = null;
  111. TheBuffer = null;
  112. }
  113. DisposedAlready = true;
  114. }
  115. public override void Flush () {
  116. if (DisposedAlready)
  117. throw new ObjectDisposedException("StreamWriter");
  118. if (pos > 0) {
  119. internalStream.Write (TheBuffer, 0, pos);
  120. internalStream.Flush ();
  121. pos = 0;
  122. }
  123. }
  124. public override void Write (char[] buffer, int index, int count) {
  125. if (DisposedAlready)
  126. throw new ObjectDisposedException("StreamWriter");
  127. byte[] res = new byte [internalEncoding.GetByteCount (buffer)];
  128. int len;
  129. int BytesToBuffer;
  130. int resPos = 0;
  131. len = internalEncoding.GetBytes (buffer, index, count, res, 0);
  132. // if they want AutoFlush, don't bother buffering
  133. if (iflush) {
  134. Flush();
  135. internalStream.Write (res, 0, len);
  136. internalStream.Flush ();
  137. } else {
  138. // otherwise use the buffer.
  139. // NOTE: this logic is not optimized for performance.
  140. while (resPos < len) {
  141. // fill the buffer if we've got more bytes than will fit
  142. BytesToBuffer = Math.Min(BufferSize - pos, len - resPos);
  143. Array.Copy(res, resPos, TheBuffer, pos, BytesToBuffer);
  144. resPos += BytesToBuffer;
  145. pos += BytesToBuffer;
  146. // if the buffer is full, flush it out.
  147. if (pos == BufferSize) Flush();
  148. }
  149. }
  150. }
  151. public override void Write(string value) {
  152. if (DisposedAlready)
  153. throw new ObjectDisposedException("StreamWriter");
  154. if (value != null)
  155. Write (value.ToCharArray (), 0, value.Length);
  156. }
  157. public override void Close() {
  158. Dispose();
  159. }
  160. ~StreamWriter() {
  161. Dispose(false);
  162. }
  163. }
  164. }