[Mono-list] Buffering for StreamWriter

Nick Drochak ndrochak@gol.com
Thu, 16 May 2002 16:52:05 +0900


This is a multi-part message in MIME format.

------=_NextPart_000_000D_01C1FCFA.02204F60
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

RxDan,

I've added buffering to StreamWriter.  I had to tweak System.Console too in
order for it to work properly.  As the docs say, you must call Close() on
the stream writer to ensure the buffer is written to the stream.  So, I made
Console use AutoFlush on the stream writer.

Seems to work. Unit tests are passing, etc.  I haven't tried making mcs or
anything.

Please review the patches and let me know how stupid I was.

Thanks,
Nick D.

------=_NextPart_000_000D_01C1FCFA.02204F60
Content-Type: application/octet-stream;
	name="StreamWriter.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="StreamWriter.patch"

Index: StreamWriter.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: /cvs/public/mcs/class/corlib/System.IO/StreamWriter.cs,v=0A=
retrieving revision 1.7=0A=
diff -u -r1.7 StreamWriter.cs=0A=
--- StreamWriter.cs	14 May 2002 11:46:20 -0000	1.7=0A=
+++ StreamWriter.cs	16 May 2002 03:55:29 -0000=0A=
@@ -8,11 +8,12 @@=0A=
 //
=20
 using System.Text;
+using System;
=20
 namespace System.IO {
 =09
 	[Serializable]
-        public class StreamWriter : TextWriter {
+	public class StreamWriter : TextWriter {
=20
 		private Encoding internalEncoding;
=20
@@ -21,17 +22,33 @@=0A=
=20
 		private bool iflush;
 	=09
-                // new public static readonly StreamWriter Null;
+		private const int DefaultBufferSize =3D 1024;
+		private const int DefaultFileBufferSize =3D 4096;
+		private const int MinimumBufferSize =3D 2;
+
+		private int pos;
+		private int BufferSize;
+		private byte[] TheBuffer;
+
+		private bool DisposedAlready =3D false;
+
+		// new public static readonly StreamWriter Null;
=20
 		public StreamWriter (Stream stream)
-			: this (stream, Encoding.UTF8, 0) {}
+			: this (stream, Encoding.UTF8, DefaultBufferSize) {}
=20
 		public StreamWriter (Stream stream, Encoding encoding)
-			: this (stream, encoding, 0) {}
+			: this (stream, encoding, DefaultBufferSize) {}
=20
-		[MonoTODO("Nothing is done with bufferSize")]
-		public StreamWriter (Stream stream, Encoding encoding, int =
bufferSize)
-		{
+		protected void Initialize(Encoding encoding, int bufferSize) {
+			internalEncoding =3D encoding;
+			pos =3D 0;
+			BufferSize =3D Math.Max(bufferSize, MinimumBufferSize);
+			TheBuffer =3D new byte[BufferSize];
+		}
+
+		//[MonoTODO("Nothing is done with bufferSize")]
+		public StreamWriter (Stream stream, Encoding encoding, int =
bufferSize) {
 			if (null =3D=3D stream)
 				throw new ArgumentNullException("stream");
 			if (null =3D=3D encoding)
@@ -42,20 +59,20 @@=0A=
 				throw new ArgumentException("bufferSize");
=20
 			internalStream =3D stream;
-			internalEncoding =3D encoding;
+
+			Initialize(encoding, bufferSize);
 		}
=20
 		public StreamWriter (string path)
-			: this (path, false, Encoding.UTF8, 0) {}
+			: this (path, false, Encoding.UTF8, DefaultFileBufferSize) {}
=20
 		public StreamWriter (string path, bool append)
-			: this (path, append, Encoding.UTF8, 0) {}
+			: this (path, append, Encoding.UTF8, DefaultFileBufferSize) {}
=20
 		public StreamWriter (string path, bool append, Encoding encoding)
-			: this (path, append, encoding, 0) {}
+			: this (path, append, encoding, DefaultFileBufferSize) {}
 	=09
-		public StreamWriter (string path, bool append, Encoding encoding, int =
bufferSize)
-		{
+		public StreamWriter (string path, bool append, Encoding encoding, int =
bufferSize) {
 			if (null =3D=3D path)
 				throw new ArgumentNullException("path");
 			if (String.Empty =3D=3D path)
@@ -86,77 +103,84 @@=0A=
 			else
 				internalStream.SetLength (0);
=20
-			internalEncoding =3D encoding;
-		=09
+			Initialize(encoding, bufferSize);
 		}
=20
-		public virtual bool AutoFlush
-		{
-
+		public virtual bool AutoFlush {
 			get {
 				return iflush;
 			}
-
 			set {
 				iflush =3D value;
 			}
 		}
=20
-		public virtual Stream BaseStream
-		{
+		public virtual Stream BaseStream {
 			get {
 				return internalStream;
 			}
 		}
=20
-		public override Encoding Encoding
-		{
+		public override Encoding Encoding {
 			get {
 				return internalEncoding;
 			}
 		}
=20
-		protected override void Dispose (bool disposing)
-		{
-			if (disposing && internalStream !=3D null) {
+		protected override void Dispose (bool disposing) {
+			if (!DisposedAlready && internalStream !=3D null) {
+				Flush();
 				internalStream.Close ();
 				internalStream =3D null;
 			}
+			DisposedAlready =3D true;
 		}
=20
-		public override void Flush ()
-		{
+		public override void Flush () {
 			if (closed)
 				throw new ObjectDisposedException("TextWriter");
=20
-			internalStream.Flush ();
+			if (pos > 0) {
+				internalStream.Write (TheBuffer, 0, pos);
+				internalStream.Flush ();
+				pos =3D 0;
+			}
 		}
 	=09
-		public override void Write (char[] buffer, int index, int count)
-		{
+		public override void Write (char[] buffer, int index, int count) {
 			byte[] res =3D new byte [internalEncoding.GetMaxByteCount =
(buffer.Length)];
 			int len;
+			int BytesToBuffer;
+			int resPos =3D 0;
=20
-			len =3D internalEncoding.GetBytes (buffer, index, count, res, 0);
-
-			internalStream.Write (res, 0, len);
-
-			if (iflush)
-				Flush ();
-		=09
+			// if they want AutoFlush, don't bother buffering
+			if (iflush) {
+				Flush();
+				internalStream.Write (res, 0, len);
+				internalStream.Flush ();
+			} else {
+				// otherwise use the buffer.
+				// NOTE: this logic is not optimized for performance.
+				len =3D internalEncoding.GetBytes (buffer, index, count, res, 0);
+				while (resPos < len) {
+					// fill the buffer if we've got more bytes than will fit
+					BytesToBuffer =3D Math.Min(BufferSize - pos, len - resPos);
+					Array.Copy(res, resPos, TheBuffer, pos, BytesToBuffer);
+					resPos +=3D BytesToBuffer;
+					pos +=3D BytesToBuffer;
+					// if the buffer is full, flush it out.
+					if (pos =3D=3D BufferSize) Flush();
+				}
+			}
 		}
=20
-		public override void Write(string value)
-		{
+		public override void Write(string value) {
 			Write (value.ToCharArray (), 0, value.Length);
 		}
=20
-		public override void Close()
-		{
+		public override void Close() {
 			Dispose(true);
 			closed =3D true;
 		}
-        }
-}
-                       =20
-                       =20
+	}
+}=0A=
\ No newline at end of file=0A=

------=_NextPart_000_000D_01C1FCFA.02204F60
Content-Type: application/octet-stream;
	name="Console.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="Console.patch"

Index: Console.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: /cvs/public/mcs/class/corlib/System/Console.cs,v=0A=
retrieving revision 1.7=0A=
diff -u -r1.7 Console.cs=0A=
--- Console.cs	1 Apr 2002 06:07:40 -0000	1.7=0A=
+++ Console.cs	16 May 2002 03:48:41 -0000=0A=
@@ -20,7 +20,9 @@=0A=
 		static Console ()=0A=
 		{=0A=
 			stderr =3D new StreamWriter (OpenStandardError ());=0A=
+			((StreamWriter)stderr).AutoFlush =3D true;=0A=
 			stdout =3D new StreamWriter (OpenStandardOutput ());=0A=
+			((StreamWriter)stdout).AutoFlush =3D true;=0A=
 			stdin  =3D new StreamReader (OpenStandardInput ());=0A=
 		}=0A=
 =0A=

------=_NextPart_000_000D_01C1FCFA.02204F60--