Stream.CopyTo method for < 4.0 framework

The .NET Framework 4.0 introduced the CopyTo() method for the Stream class. (http://msdn.microsoft.com/en-us/library/system.io.stream.copyto.aspx)

You copy a stream into one other this way:


   MemoryStream memoryStream = new MemoryStream();
   using (Stream stream = new FileStream(@"c:\input.txt", FileMode.Open))
   {
      stream.CopyTo(memoryStream);
   }

If you are stucked with a lower version of the framework, you might want to use it anyway.

A bit of reflector is realy usefull to see how the implementation is done in 4.0.

The CopyTo method :


public void CopyTo(Stream destination)
{
    if (destination == null)
    {
        throw new ArgumentNullException("destination");
    }
    if (!this.CanRead && !this.CanWrite)
    {
        throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
    }
    if (!destination.CanRead && !destination.CanWrite)
    {
        throw new ObjectDisposedException("destination", Environment.GetResourceString("ObjectDisposed_StreamClosed"));
    }
    if (!this.CanRead)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
    }
    if (!destination.CanWrite)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
    }
    this.InternalCopyTo(destination, 0x1000);
}

We see that the InternalCopyTo is used :


private void InternalCopyTo(Stream destination, int bufferSize)
{
    int num;
    byte[] buffer = new byte[bufferSize];
    while ((num = this.Read(buffer, 0, buffer.Length)) != 0)
    {
        destination.Write(buffer, 0, num);
    }
}

Remark :
0×1000 is in hexadecimal, which corresponds to 4096 in decimal.

So we can retrieve that for use with lower versions of the language

For .NET FX >= 3.0 you can create an extension method


    using System;
    using System.IO;

    /// <summary>
    /// Extension methods for streams.
    /// </summary>
    public static class StreamExtensions
    {
        /// <summary>
        /// Reads all the bytes from the current stream and writes them to the destination stream.
        /// </summary>
        /// <param name="original">The current stream.</param>
        /// <param name="destination">The stream that will contain the contents of the current stream.</param>
        /// <exception cref="System.ArgumentNullException">Destination is null.</exception>
        /// <exception cref="System.NotSupportedException">The current stream does not support reading.-or-destination does not support Writing.</exception>
        /// <exception cref="System.ObjectDisposedException">Either the current stream or destination were closed before the System.IO.Stream.CopyTo(System.IO.Stream) method was called.</exception>
        /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
        public static void CopyTo(this Stream original, Stream destination)
        {
            if (destination == null)
            {
                throw new ArgumentNullException("destination");
            }
            if (!original.CanRead && !original.CanWrite)
            {
                throw new ObjectDisposedException("ObjectDisposedException");
            }
            if (!destination.CanRead && !destination.CanWrite)
            {
                throw new ObjectDisposedException("ObjectDisposedException");
            }
            if (!original.CanRead)
            {
                throw new NotSupportedException("NotSupportedException source");
            }
            if (!destination.CanWrite)
            {
                throw new NotSupportedException("NotSupportedException destination");
            }

            byte[] array = new byte[4096];
            int count;
            while ((count = original.Read(array, 0, array.Length)) != 0)
            {
                destination.Write(array, 0, count);
            }
        }
    }

You use it this way (same ways as the FX 4.0):


   MemoryStream memoryStream = new MemoryStream();
   using (Stream stream = new FileStream(@"c:\input.txt", FileMode.Open))
   {
      stream.CopyTo(memoryStream);
   }

For lower version, you can create an helper class.


    using System;
    using System.IO;

    /// <summary>
    /// An helper class for streams.
    /// </summary>
    public class StreamHelper
    {
        /// <summary>
        /// Reads all the bytes from the current stream and writes them to the destination stream.
        /// </summary>
        /// <param name="original">The original stream.</param>
        /// <param name="destination">The stream that will contain the contents of the current stream.</param>
        /// <exception cref="System.ArgumentNullException">Destination is null.</exception>
        /// <exception cref="System.NotSupportedException">The current stream does not support reading.-or-destination does not support Writing.</exception>
        /// <exception cref="System.ObjectDisposedException">Either the current stream or destination were closed before the System.IO.Stream.CopyTo(System.IO.Stream) method was called.</exception>
        /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
        public static void CopyStreamTo(Stream original, Stream destination)
        {
            if (destination == null)
            {
                throw new ArgumentNullException("destination");
            }
            if (!original.CanRead && !original.CanWrite)
            {
                throw new ObjectDisposedException("ObjectDisposedException");
            }
            if (!destination.CanRead && !destination.CanWrite)
            {
                throw new ObjectDisposedException("ObjectDisposedException");
            }
            if (!original.CanRead)
            {
                throw new NotSupportedException("NotSupportedException source");
            }
            if (!destination.CanWrite)
            {
                throw new NotSupportedException("NotSupportedException destination");
            }

            byte[] array = new byte[4096];
            int count;
            while ((count = original.Read(array, 0, array.Length)) != 0)
            {
                destination.Write(array, 0, count);
            }
        }
    }

Use it this way:


   MemoryStream memoryStream = new MemoryStream();
   using (Stream stream = new FileStream(@"c:\input.txt", FileMode.Open))
   {
        StreamHelper.CopyStreamTo(stream, memoryStream);
   }
   

Incoming search terms:

  • FileStream CopyTo
  • stream copyto
  • Stream does not support reading
  • FileSteam CopyTo New Destination
  • C# FileStream CopyTo
  • stream copyto cannot access a closed stream
  • c# filestream to memorystream
  • c# filestream copyto example
  • c# filestream copyto count bytes
  • c# cannot access a closed stream copyTo

About Sam Beauvois

Application Developer, .NET enthusiast since 2004, I'm interested in technology watch, usability, code quality, patterns & practices, UX, ...

3 comments

  1. admin says:

    Nice, thanks :)

    you can also do it this way:

    greaterStream = Math.Max(original.Length, destination.Length);

  2. Mark says:

    Wonderful! I just didn’t like that fixed length bytes array. I did like this, in order to get the stream with the greater length:
    long greaterStream;
    if (original.Length > destination.Length)
    greaterStream = original.Length;
    else
    greaterStream = destination.Length;

    byte[] array = new byte[greaterStream];

    I have to deal with 120mb xmls for that copy so i find this useful.

  3. Waldek says:

    Hi Sam,

    Thank you for this post. It saved me time and I avoided necessity of converstion to .NET 4. Anyway I write for SharePoint which supports (currently) only .NET 3.5, so I cannot convert my project to .NET 4.

    Waldek

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>