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