singrdk/base/Libraries/System.IO/Stream.cs

315 lines
11 KiB
C#
Raw Permalink Normal View History

2008-03-05 09:52:00 -05:00
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
2008-11-17 18:29:00 -05:00
//============================================================
//
// Class: Stream
//
// Purpose: Abstract base class for all Streams. Provides
// default implementations of asynchronous reads & writes, in
// terms of the synchronous reads & writes (and vice versa).
//
//===========================================================
2008-03-05 09:52:00 -05:00
using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
2008-11-17 18:29:00 -05:00
namespace System.IO
{
2008-03-05 09:52:00 -05:00
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream"]/*' />
[CCtorIsRunDuringStartup]
public abstract class Stream : IDisposable {
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Null"]/*' />
public static readonly Stream Null = new NullStream();
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.CanRead"]/*' />
public abstract bool CanRead {
get;
}
// If CanSeek is false, Position, Seek, Length, and SetLength should throw.
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.CanSeek"]/*' />
public abstract bool CanSeek {
get;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.CanWrite"]/*' />
public abstract bool CanWrite {
get;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Length"]/*' />
public abstract long Length {
get;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Position"]/*' />
public abstract long Position {
get;
set;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Close"]/*' />
public virtual void Close()
{
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.IDisposable.Dispose"]/*' />
/// <internalonly/>
void IDisposable.Dispose()
{
Close();
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Flush"]/*' />
public abstract void Flush();
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.CreateWaitHandle"]/*' />
[CLSCompliant(false)]
protected virtual WaitHandle CreateWaitHandle()
{
return new ManualResetEvent(false);
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.BeginRead"]/*' />
public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object _state)
{
if (!CanRead) __Error.ReadNotSupported();
// To avoid a race with a stream's position pointer & generating race
// conditions with internal buffer indexes in our own streams that
// don't natively support async IO operations when there are multiple
// async requests outstanding, we will block the application's main
// thread and do the IO synchronously.
SynchronousAsyncResult asyncResult = new SynchronousAsyncResult(_state, false);
try {
int numRead = Read(buffer, offset, count);
asyncResult._numRead = numRead;
asyncResult._isCompleted = true;
asyncResult._waitHandle.Set();
}
catch (IOException e) {
asyncResult._exception = e;
}
if (callback != null)
callback(asyncResult);
return asyncResult;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.EndRead"]/*' />
public virtual int EndRead(IAsyncResult asyncResult)
{
if (asyncResult == null)
throw new ArgumentNullException("asyncResult");
SynchronousAsyncResult ar = asyncResult as SynchronousAsyncResult;
if (ar == null || ar.IsWrite) {
__Error.WrongAsyncResult();
assume false; // never gets here
}
if (ar._EndXxxCalled) {
__Error.EndReadCalledTwice();
assume false; // never gets here
}
ar._EndXxxCalled = true;
if (ar._exception != null)
throw ar._exception;
return ar._numRead;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.BeginWrite"]/*' />
public virtual IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object _state)
{
if (!CanWrite) __Error.WriteNotSupported();
// To avoid a race with a stream's position pointer & generating race
// conditions with internal buffer indexes in our own streams that
// don't natively support async IO operations when there are multiple
// async requests outstanding, we will block the application's main
// thread and do the IO synchronously.
SynchronousAsyncResult asyncResult = new SynchronousAsyncResult(_state, true);
try {
Write(buffer, offset, count);
asyncResult._isCompleted = true;
asyncResult._waitHandle.Set();
}
catch (IOException e) {
asyncResult._exception = e;
}
if (callback != null)
callback.BeginInvoke(asyncResult, null, null);
return asyncResult;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.EndWrite"]/*' />
public virtual void EndWrite(IAsyncResult asyncResult)
{
2008-11-17 18:29:00 -05:00
if (asyncResult == null)
2008-03-05 09:52:00 -05:00
throw new ArgumentNullException("asyncResult");
SynchronousAsyncResult ar = asyncResult as SynchronousAsyncResult;
if (ar == null || !ar.IsWrite) {
__Error.WrongAsyncResult();
assume false; // never gets here
}
if (ar._EndXxxCalled) {
__Error.EndWriteCalledTwice();
assume false; // never gets here
}
ar._EndXxxCalled = true;
if (ar._exception != null)
throw ar._exception;
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Seek"]/*' />
public abstract long Seek(long offset, SeekOrigin origin);
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.SetLength"]/*' />
public abstract void SetLength(long value);
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Read"]/*' />
public abstract int Read([In, Out] byte[] buffer, int offset, int count);
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.ReadByte"]/*' />
public virtual int ReadByte()
{
// Reads one byte from the stream by calling Read(byte[], int, int).
// Will return an unsigned byte cast to an int or -1 on end of stream.
// The performance of the default implementation on Stream is bad,
// and any subclass with an internal buffer should override this method.
byte[] oneByteArray = new byte[1];
int r = Read(oneByteArray, 0, 1);
2008-11-17 18:29:00 -05:00
if (r == 0)
2008-03-05 09:52:00 -05:00
return -1;
return oneByteArray[0];
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.Write"]/*' />
public abstract void Write(byte[] buffer, int offset, int count);
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.WriteByte"]/*' />
public virtual void WriteByte(byte value)
{
// Writes one byte from the stream by calling Write(byte[], int, int).
// The performance of the default implementation on Stream is bad,
// and any subclass with an internal buffer should override this method.
byte[] oneByteArray = new byte[1];
oneByteArray[0] = value;
Write(oneByteArray, 0, 1);
}
// No data, no need to serialize
private class NullStream : Stream
{
protected internal NullStream() {}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.NullStream.CanRead"]/*' />
public override bool CanRead {
get { return true; }
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.NullStream.CanWrite"]/*' />
public override bool CanWrite {
get { return true; }
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.NullStream.CanSeek"]/*' />
public override bool CanSeek {
get { return true; }
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.NullStream.Length"]/*' />
public override long Length {
get { return 0; }
}
//| <include file='doc\Stream.uex' path='docs/doc[@for="Stream.NullStream.Position"]/*' />
public override long Position {
get { return 0; }
set {}
}
public override void Close()
{
}
public override void Flush()
{
}
public override int Read([In, Out] byte[] buffer, int offset, int count)
{
return 0;
}
public override void Write(byte[] buffer, int offset, int count)
{
}
public override long Seek(long offset, SeekOrigin origin)
{
return 0;
}
public override void SetLength(long length)
{
}
}
// Used as the IAsyncResult object when using asynchronous IO methods
// on the base Stream class. Note I'm not using async delegates, so
// this is necessary.
private sealed class SynchronousAsyncResult : IAsyncResult
{
internal ManualResetEvent _waitHandle;
internal Object _stateObject;
internal int _numRead;
internal bool _isCompleted;
internal bool _isWrite;
internal bool _EndXxxCalled;
internal Exception _exception;
internal SynchronousAsyncResult(Object asyncStateObject, bool isWrite)
{
_stateObject = asyncStateObject;
_isWrite = isWrite;
_waitHandle = new ManualResetEvent(false);
}
public bool IsCompleted {
get { return _isCompleted; }
}
public WaitHandle AsyncWaitHandle {
get { return _waitHandle; }
}
public Object AsyncState {
get { return _stateObject; }
}
public bool CompletedSynchronously {
get { return true; }
}
internal bool IsWrite {
get { return _isWrite; }
}
}
}
}