StreamWriter.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. private bool preamble_done = false;
  26. public new static readonly StreamWriter Null = new StreamWriter (Stream.Null, Encoding.UTF8Unmarked, 0);
  27. public StreamWriter (Stream stream)
  28. : this (stream, Encoding.UTF8Unmarked, DefaultBufferSize) {}
  29. public StreamWriter (Stream stream, Encoding encoding)
  30. : this (stream, encoding, DefaultBufferSize) {}
  31. internal void Initialize(Encoding encoding, int bufferSize) {
  32. internalEncoding = encoding;
  33. pos = 0;
  34. BufferSize = Math.Max(bufferSize, MinimumBufferSize);
  35. TheBuffer = new byte[BufferSize];
  36. }
  37. //[MonoTODO("Nothing is done with bufferSize")]
  38. public StreamWriter (Stream stream, Encoding encoding, int bufferSize) {
  39. if (null == stream)
  40. throw new ArgumentNullException("stream");
  41. if (null == encoding)
  42. throw new ArgumentNullException("encoding");
  43. if (bufferSize < 0)
  44. throw new ArgumentOutOfRangeException("bufferSize");
  45. if (!stream.CanWrite)
  46. throw new ArgumentException("bufferSize");
  47. internalStream = stream;
  48. Initialize(encoding, bufferSize);
  49. }
  50. public StreamWriter (string path)
  51. : this (path, false, Encoding.UTF8Unmarked, DefaultFileBufferSize) {}
  52. public StreamWriter (string path, bool append)
  53. : this (path, append, Encoding.UTF8Unmarked, DefaultFileBufferSize) {}
  54. public StreamWriter (string path, bool append, Encoding encoding)
  55. : this (path, append, encoding, DefaultFileBufferSize) {}
  56. public StreamWriter (string path, bool append, Encoding encoding, int bufferSize) {
  57. if (null == path)
  58. throw new ArgumentNullException("path");
  59. if (String.Empty == path)
  60. throw new ArgumentException("path cannot be empty string");
  61. if (path.IndexOfAny (Path.InvalidPathChars) != -1)
  62. throw new ArgumentException("path contains invalid characters");
  63. if (null == encoding)
  64. throw new ArgumentNullException("encoding");
  65. if (bufferSize < 0)
  66. throw new ArgumentOutOfRangeException("bufferSize");
  67. string DirName = Path.GetDirectoryName(path);
  68. if (DirName != String.Empty && !Directory.Exists(DirName))
  69. throw new DirectoryNotFoundException();
  70. FileMode mode;
  71. if (append)
  72. mode = FileMode.Append;
  73. else
  74. mode = FileMode.Create;
  75. internalStream = new FileStream (path, mode, FileAccess.Write);
  76. if (append)
  77. internalStream.Position = internalStream.Length;
  78. else
  79. internalStream.SetLength (0);
  80. Initialize(encoding, bufferSize);
  81. }
  82. public virtual bool AutoFlush {
  83. get {
  84. return iflush;
  85. }
  86. set {
  87. iflush = value;
  88. }
  89. }
  90. public virtual Stream BaseStream {
  91. get {
  92. return internalStream;
  93. }
  94. }
  95. public override Encoding Encoding {
  96. get {
  97. return internalEncoding;
  98. }
  99. }
  100. protected override void Dispose (bool disposing) {
  101. if (!DisposedAlready && disposing && internalStream != null) {
  102. Flush();
  103. DisposedAlready = true;
  104. internalStream.Close ();
  105. }
  106. internalStream = null;
  107. TheBuffer = null;
  108. internalEncoding = null;
  109. }
  110. public override void Flush () {
  111. if (DisposedAlready)
  112. throw new ObjectDisposedException("StreamWriter");
  113. if (pos > 0) {
  114. internalStream.Write (TheBuffer, 0, pos);
  115. internalStream.Flush ();
  116. pos = 0;
  117. }
  118. }
  119. public override void Write (char[] buffer, int index, int count) {
  120. if (DisposedAlready)
  121. throw new ObjectDisposedException("StreamWriter");
  122. byte[] res = new byte [internalEncoding.GetByteCount (buffer)];
  123. int len;
  124. int BytesToBuffer;
  125. int resPos = 0;
  126. len = internalEncoding.GetBytes (buffer, index, count, res, 0);
  127. // write the encoding preamble only at the start of the stream
  128. if (!preamble_done && len > 0) {
  129. byte[] preamble = internalEncoding.GetPreamble ();
  130. if (preamble.Length > 0)
  131. internalStream.Write (preamble, 0, preamble.Length);
  132. preamble_done = true;
  133. }
  134. // if they want AutoFlush, don't bother buffering
  135. if (iflush) {
  136. Flush();
  137. internalStream.Write (res, 0, len);
  138. internalStream.Flush ();
  139. } else {
  140. // otherwise use the buffer.
  141. // NOTE: this logic is not optimized for performance.
  142. while (resPos < len) {
  143. // fill the buffer if we've got more bytes than will fit
  144. BytesToBuffer = Math.Min(BufferSize - pos, len - resPos);
  145. Array.Copy(res, resPos, TheBuffer, pos, BytesToBuffer);
  146. resPos += BytesToBuffer;
  147. pos += BytesToBuffer;
  148. // if the buffer is full, flush it out.
  149. if (pos == BufferSize) Flush();
  150. }
  151. }
  152. }
  153. public override void Write (char value)
  154. {
  155. Write (new char [] {value}, 0, 1);
  156. }
  157. public override void Write (char [] value)
  158. {
  159. Write (value, 0, value.Length);
  160. }
  161. public override void Write(string value) {
  162. if (DisposedAlready)
  163. throw new ObjectDisposedException("StreamWriter");
  164. if (value != null)
  165. Write (value.ToCharArray (), 0, value.Length);
  166. }
  167. public override void Close()
  168. {
  169. Dispose (true);
  170. }
  171. ~StreamWriter() {
  172. Dispose(false);
  173. }
  174. }
  175. }