Utility class that provides methods to manipulate stream of data. : Stream Read Write « File Stream « C# / C Sharp






Utility class that provides methods to manipulate stream of data.

  
#region License and Copyright
/* -------------------------------------------------------------------------
 * Dotnet Commons IO
 *
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 
 * for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this library; if not, write to the 
 * 
 * Free Software Foundation, Inc., 
 * 59 Temple Place, 
 * Suite 330, 
 * Boston, 
 * MA 02111-1307 
 * USA 
 * 
 * -------------------------------------------------------------------------
 */
#endregion

using System;
using System.IO;
using System.Text;

namespace Dotnet.Commons.IO
{
  /// <summary>
  /// Utility class that provides methods to manipulate stream of data.
  /// </summary>
  /// <remarks>
    /// This class is ported from <a href="http://jakarta.apache.org/commons/io/">Jakarta Commons IO</a> org.apache.commons.io.CopyUtils class.
    /// 
  /// This class also contains code taken from an article written by Jon Skeet. The 
    /// article can be found here: <a href="http://www.developerfusion.co.uk/show/4696/">
    /// http://www.developerfusion.co.uk/show/4696/</a>
  /// </remarks>
  public sealed class StreamUtils
  {
        /// <summary> The name says it all.</summary>
        private const int DEFAULT_BUFFER_SIZE = 1024 * 4;
    

    private StreamUtils(){}


        public static void Copy(byte[] input, byte[] output, long outputOffset)
        {
            if (input.Length == 0) return;

            for (int i=0; i<input.Length; i++)
            {
                output[outputOffset + i] = input[i];
            }
        }


        /// <summary> Copy bytes from a <see cref="byte"/>[] to an Output <see cref="Stream"/>.</summary>
        /// <param name="input">the byte array to read from
        /// </param>
        /// <param name="output">the Output <see cref="Stream"/> to write to
        /// </param>
        /// <exception cref="IOException">if an I/O problem occurs</exception>    
        public static void Copy(byte[] input, Stream output)
        {
            if (input.Length == 0) return;
            
            output.Write(input, 0, input.Length);
        }


        /// <summary>
        /// Copy and convert bytes from a <see cref="byte"/>[] to chars on a
        /// <see cref="StreamWriter"/>.
        /// </summary>
        /// <param name="input">the byte array to read from</param>
        /// <param name="outputWriter">the <see cref="StreamWriter"/> to write to</param>
        /// <exception cref="IOException">in the case of an I/O problem</exception>
        public static void Copy(byte[] input, StreamWriter outputWriter)
        {
            MemoryStream inputStream = new MemoryStream(input);
            Copy(inputStream, outputWriter);
        }


        /// <summary>
        ///  Copy and convert bytes from a <see cref="byte"/>[] to chars on a
        /// <see cref="StreamWriter"/>.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="outputWriter"></param>
        /// <param name="encoding"></param>
        public static void Copy(byte[] input, StreamWriter outputWriter, string encoding)
        {
            MemoryStream inputStream = new MemoryStream(input);
            Copy(inputStream, outputWriter, encoding);
        }

        /// <summary> Copy the entire content from an Input <see cref="Stream"/> to an Output <see cref="Stream"/>.</summary>
        /// <param name="input">the Input <see cref="Stream"/>to read from the beginning of the stream
        /// </param>
        /// <param name="output">the Output <see cref="Stream"/> to write to
        /// </param>        
        /// <returns> the number of bytes copied        
        /// </returns>
        /// <exception cref="IOException">if an I/O problem occurs</exception>    
        public static int Copy(Stream input, Stream output)
        {
            return Copy(input, output, false);
        }


        /// <summary> Copy bytes from an Input <see cref="Stream"/> to an Output <see cref="Stream"/>.</summary>
        /// <param name="input">the Input <see cref="Stream"/>to read from
        /// </param>
        /// <param name="output">the Output <see cref="Stream"/> to write to
        /// </param>
        /// <param name="copyFromBeginning">Set true to copy from the beginning of the input stream, eg. input.Position=0,
        /// otherwise, it will start copying from whatever the current position in the input stream. 
        /// </param>
        /// <returns> the number of bytes copied        
        /// </returns>
        /// <exception cref="IOException">if an I/O problem occurs</exception>
        public static int Copy(Stream input, Stream output, bool copyFromBeginning)
        {
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int bytesRead = 0;
            int len = DEFAULT_BUFFER_SIZE;
            int offset=0;

            if (copyFromBeginning) 
                input.Seek(0, SeekOrigin.Begin);

            // set it to the beginning            
            while (len > 0)
            {
                len = input.Read(buffer, offset, DEFAULT_BUFFER_SIZE);
                output.Write(buffer, 0, len);
                bytesRead += len;
            }
            
            return bytesRead;
        }
   

        // ----------------------------------------------------------------
        // Reader -> Writer
        // ----------------------------------------------------------------

        /// <summary> Copy chars from a <see cref="StreamReader"/>  to a <see cref="StreamWriter"/>.</summary>
        /// <param name="inputStreamReader">the <see cref="StreamReader"/> to read from
        /// </param>
        /// <param name="outputStreamWriter">the <see cref="StreamWriter"/> to write to
        /// </param>
        /// <returns> the number of characters copied
        /// </returns>        
        /// <exception cref="IOException">if an I/O problem occurs</exception>
        public static int Copy(StreamReader inputStreamReader, StreamWriter outputStreamWriter)
        {
            char[] buffer = new char[DEFAULT_BUFFER_SIZE];
            int count = 0;            
            int len = DEFAULT_BUFFER_SIZE;
                        
            while (len > 0)
            {
                len = inputStreamReader.Read(buffer, 0, DEFAULT_BUFFER_SIZE);
                outputStreamWriter.Write(buffer, 0, len);
                count += len;
            }
            return count;
        }

        // ----------------------------------------------------------------
        // InputStream -> Writer
        // ----------------------------------------------------------------

        /// <summary> Copy and convert bytes from an Input <see cref="Stream"/> to chars on a
        /// <see cref="StreamWriter"/>.
        /// The platform's default encoding is used for the byte-to-char conversion.
        /// </summary>
        /// <param name="inputStream">the Input <see cref="Stream"/> to read from
        /// </param>
        /// <param name="outputStreamWriter">the <see cref="StreamWriter"/>to write to
        /// </param>
        /// <exception cref="IOException">if an I/O problem occurs</exception>
        public static int Copy(Stream inputStream, StreamWriter outputStreamWriter)
        {
            StreamReader inputStreamReader = new StreamReader(inputStream, System.Text.Encoding.Default);
            return Copy(inputStreamReader, outputStreamWriter);
        }
        
        /// <summary>
        /// Copy and convert bytes from an Input <see cref="Stream"/> to chars on a
        /// <see cref="StreamWriter"/>, using the specified encoding.
        /// </summary>
        /// <param name="inputStream"></param>
        /// <param name="outputWriter"></param>
        /// <param name="encoding">The name of a supported character encoding. See the
        /// <a href="http://www.iana.org/assignments/character-sets">IANA
        /// Charset Registry</a> and <a href="http://msdn2.microsoft.com/en-us/library/system.text.encoding.aspx">MSDN: Encoding class</a>
        /// for a list of valid encoding types.</param>
        /// <exception cref="IOException">an I/O problem occurs</exception>
        public static int Copy(Stream inputStream, StreamWriter outputWriter, String encoding)
        {
            Encoding encode = Encoding.Default;

            try
            {
                encode = Encoding.GetEncoding(encoding);
            }
            catch
            {
                encode = Encoding.Default;
            }
            StreamReader inputStreamReader = new StreamReader(inputStream, encode);
            return Copy(inputStreamReader, outputWriter);
        }


        // ----------------------------------------------------------------
        // Reader -> OutputStream
        // ----------------------------------------------------------------

        /// <summary>
        /// Serialize chars from a <see cref="StreamReader"/> to bytes on an 
        /// Output <see cref="Stream"/>, and flush the Output <see cref="Stream"/>.
        /// </summary>
        /// <param name="inputReader">the <see cref="StreamReader"/> to read from</param>
        /// <param name="output">the  <see cref="Stream"/> to write to</param>
        /// <exception cref="IOException">an I/O problem occurs</exception>
        public static void Copy(StreamReader inputReader, Stream output)
        {
            StreamWriter outputWriter = new StreamWriter(output, System.Text.Encoding.Default);
            Copy(inputReader, outputWriter);

            outputWriter.Flush();
        }

        // ----------------------------------------------------------------
        // String -> OutputStream
        // ----------------------------------------------------------------
        /// <summary> Serialize chars from a <see cref="String"/> to bytes on an 
        /// Output <see cref="Stream"/>, and
        /// flush the Output <see cref="Stream"/>.
        /// </summary>
        /// <param name="input">the <see cref="String"/> to read from
        /// </param>
        /// <param name="output">the Output <see cref="Stream"/> to write to
        /// </param>        
        /// <exception cref="IOException">an I/O problem occurs</exception>
        public static void Copy(String input, Stream output)
        {
            byte[] inputByteArray = new ASCIIEncoding().GetBytes(input);
            StreamWriter outWriter = new StreamWriter(output, System.Text.Encoding.Default);
            Copy(inputByteArray, outWriter);

            outWriter.Flush();            
        }

        // ----------------------------------------------------------------
        // String -> Writer
        // ----------------------------------------------------------------

        /// <summary> Copy chars from a <see cref="String"/> to a <see cref="StreamWriter"/>.</summary>
        /// <param name="input">the <see cref="String"/> to read from
        /// </param>
        /// <param name="output">the <see cref="StreamWriter"/> to write to
        /// </param>
        /// <exception cref="IOException">an I/O problem occurs</exception>      
        public static void Copy(String input, StreamWriter output)
        {
            output.Write(input);
        }


        /// <summary>
        /// Copy the exact number of bytes from the source <see cref="Stream"/> to a
        /// target <see cref="Stream"/>.
        /// </summary>
        /// <param name="source">Source <see cref="Stream"/> to copy from</param>
        /// <param name="target">Target <see cref="Stream"/> to copy to</param>
        /// <param name="len">number of bytes to copy</param>        
        /// <exception cref="IOException">if the source stream does not have enough data.</exception>
        public static void CopyExact(Stream source, Stream target, int len)
        {
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int bytesRead = 0;

            while (bytesRead < len)
            {
                int sizeNeeded = Math.Min(buffer.Length, len - bytesRead);
                int readSize = source.Read(buffer, 0, sizeNeeded);

                if (readSize <= 0)
                    throw new IOException(String.Format("Underlying stream does not have enough data. Read {0} bytes, but {1} needed", readSize, sizeNeeded));

                target.Write(buffer, 0, readSize);
                bytesRead += readSize;
            }
        }


    /// <summary>
    /// Reads data into a complete array, throwing an EndOfStreamException
    /// if the stream runs out of data first, or if an IOException
    /// naturally occurs.
    /// </summary>
    /// <param name="stream">The stream to read data from</param>
    /// <param name="byteArray">The array to read bytes into. The array
    /// will be completely filled from the stream, so an appropriate
    /// size must be given.</param>
    public static void ReadIntoByteArray (Stream stream, byte[] byteArray)
    {
      int offset=0;
      int remaining = byteArray.Length;
            stream.Position = 0;
      while (remaining > 0)
      {
        int read = stream.Read(byteArray, offset, remaining);
        if (read <= 0)
          throw new EndOfStreamException 
            (String.Format("End of stream reached with {0} bytes left to read", remaining));
        remaining -= read;
        offset += read;
      }
    }



    /// <summary>
    /// Reads data from the beginning of a stream until the end is reached. The
    /// data is returned as a byte array. 
    /// </summary>
    /// <param name="stream">The stream to read data from</param>
    /// <exception cref="IOException">thrown if any of the underlying IO calls fail</exception>
    /// <remarks>Use this method if you don't know the length of the stream in advance 
    /// (for instance a network stream) and just want to read the whole lot into a buffer. 
    /// <para>
    /// <strong>Note:</strong><br/>
    /// This method of reading the stream is not terribly efficient.
    /// </para>
    ///  </remarks>
    public static byte[] GetBytes(Stream stream)
    {
            if (stream is MemoryStream)
                return ((MemoryStream)stream).ToArray();

            byte[] byteArray = new byte[DEFAULT_BUFFER_SIZE];
      using (MemoryStream ms = new MemoryStream())
      {
                stream.Position = 0;
        while (true)
        {
          int readLen = stream.Read (byteArray, 0, byteArray.Length);
          if (readLen <= 0)
            return ms.ToArray();
          ms.Write (byteArray, 0, readLen);
        }
      }
    }


    /// <summary>
    /// Reads data from a stream until the end is reached. The
    /// data is returned as a byte array. 
    /// </summary>
    /// <param name="stream">The stream to read data from</param>
    /// <param name="initialLength">The initial buffer length. If the length is &lt; 1,
        /// then the default value of <see cref="Int16.MaxValue"/> will be used.
        /// </param>
    /// <exception cref="IOException">thrown if any of the underlying IO calls fail</exception>
    /// <remarks>Use this method to get the data if you know the expected length of data to start with.</remarks>
    public static byte[] GetBytes (Stream stream, long initialLength)
    {
      // If we've been passed an unhelpful initial length, just
      // use 32K.
      if (initialLength < 1)
        initialLength = Int16.MaxValue;
      
    
      byte[] buffer = new byte[initialLength];
      int read=0;
    
      int chunk;
      while ( (chunk = stream.Read(buffer, read, buffer.Length-read)) > 0)
      {
        read += chunk;
        
        // If we've reached the end of our buffer, check to see if there's
        // any more information
        if (read == buffer.Length)
        {
          int nextByte = stream.ReadByte();
            
          // End of stream? If so, we're done
          if (nextByte==-1)
          {
            return buffer;
          }
            
          // Nope. Resize the buffer, put in the byte we've just
          // read, and continue
          byte[] newBuffer = new byte[buffer.Length*2];
          Array.Copy(buffer, newBuffer, buffer.Length);
          newBuffer[read]=(byte)nextByte;
          buffer = newBuffer;
          read++;
        }
      }
      // Buffer is now too big. Shrink it.
      byte[] ret = new byte[read];
      Array.Copy(buffer, ret, read);
      return ret;
    }

    

    /// <summary>
    /// Return an ASCII string from a stream of data
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    public static string GetAsciiString(Stream stream)
    {      
      ASCIIEncoding encoding = new ASCIIEncoding();
      return GetString(stream, encoding);
    }


    /// <summary>
    /// Return an UTF8 encoded string from a stream of data
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    public static string GetString(Stream stream)
    {
      UTF8Encoding encoding = new UTF8Encoding();
      return GetString(stream, encoding);
    }

    /// <summary>
    /// Return a string from a stream. The string is returned with 
    /// the encoding provided.
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static string GetString(Stream stream, Encoding encoding)
    {

      if (stream == null)
        return string.Empty;

      byte[] bytes = new byte[stream.Length];

      if (stream is MemoryStream)
        bytes = ((MemoryStream)stream).GetBuffer();                
      else
        ReadIntoByteArray(stream, bytes);
      
      return encoding.GetString(bytes);
    }


        /// <summary>
        /// Reads the specified number of bytes from any position in a source stream into a 
        /// specific byte array in a specific start index position. The byte
        /// array must have the necessary size to read the portion of the stream required.
        /// </summary>
        /// <param name="source">Source stream to read from</param>
        /// <param name="target">Target byte array to write to</param>
        /// <param name="targetOffset">offset index in the target</param>
        /// <param name="sourceOffset">offset position in the stream</param>
        /// <param name="bytesToRead">number of bytes to read in the stream</param>
        /// <exception cref="ArgumentException">thrown if the target byte array is too small to stored
        /// the required number of bytes read from the stream.</exception>
        public static void ReadExact(Stream source, 
                                        byte[] target,
                                        int sourceOffset,
                                        int targetOffset, 
                                        int bytesToRead)
        {
            
            if (targetOffset + bytesToRead > target.Length) 
                throw new ArgumentException("target array to small");

            int bytesRead = 0;
            source.Seek(sourceOffset, SeekOrigin.Begin);
            while (bytesRead < bytesToRead) 
            {   // need more data  
                int sizeNeeded = Math.Min(DEFAULT_BUFFER_SIZE, bytesToRead - bytesRead); 
                
                // read either the whole buffer length or                   
                // the remaining # of bytes: bytesToRead - sizeNeeded 
                int readSize = source.Read(target, (targetOffset + bytesRead), sizeNeeded);

                if (readSize <= 0)
                    throw new IOException(String.Format("Underlying stream does not have enough data. Read {0} bytes, but {1} needed", readSize, sizeNeeded));

                bytesRead += readSize;
            }                        
        }


        /// <summary>
        /// Read a partial segment of a stream, starting from an offset position.
        /// </summary>
        /// <param name="source">Source stream to read from</param>
        /// <param name="sourceOffset">the starting offset position in the stream. Set to 0 if the stream is to be read from the beginning.</param>
        /// <param name="bytesToRead">number of bytes to read</param>
        /// <returns>return partial segment as an array of bytes.</returns>
        public static byte[] ReadPartial(Stream source,
                                         long sourceOffset,
                                         long bytesToRead)
        {
            long sizeDiff = source.Length - sourceOffset;
            if (bytesToRead > sizeDiff)
                throw new ArgumentException("Bytes required exceeds what is available in stream");

            byte[] target = new byte[bytesToRead];

            long bytesRead = 0;
            source.Seek(sourceOffset, SeekOrigin.Begin);

            while (bytesRead < bytesToRead)
            {   // need more data  
                int sizeNeeded = (int)Math.Min((long)DEFAULT_BUFFER_SIZE, bytesToRead - bytesRead);

                // read either the whole buffer length or                   
                // the remaining # of bytes: bytesToRead - sizeNeeded 

                int readSize = source.Read(target, 0, sizeNeeded);

                if (readSize <= 0)
                    throw new IOException(String.Format("Underlying stream does not have enough data. Read {0} bytes, but {1} needed", readSize, sizeNeeded));

                bytesRead += readSize;
            }
            return target;
        }


        /// <summary>
        /// Read a stream (like a file or HttpWebRequest) and write to another stream
        /// </summary>
        /// <param name="readStream">the stream to read</param>
        /// <param name="writeStream"> the stream to write to</param>
        [Obsolete("See StreamUtils.Copy")]
        public static void ReadWriteStream(Stream readStream, Stream writeStream)
        {            
            Byte[] buffer = new Byte[DEFAULT_BUFFER_SIZE];
            int bytesRead = readStream.Read(buffer, 0, DEFAULT_BUFFER_SIZE);
            // write the required bytes
            while (bytesRead > 0)
            {
                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = readStream.Read(buffer, 0, DEFAULT_BUFFER_SIZE);
            }
            readStream.Close();
            writeStream.Close();
        }

        

        /// <summary>
        /// Try to skip bytes in the input stream and return the actual number of bytes skipped.
        /// </summary>
        /// <param name="stream">Input stream that will be used to skip the bytes</param>
        /// <param name="skipBytes">Number of bytes to be skipped</param>
        /// <returns>Actual number of bytes skipped</returns>
        public static int Skip(Stream stream, int skipBytes)
        {
            long oldPosition = stream.Position;
            long result = stream.Seek(skipBytes, SeekOrigin.Current) - oldPosition;
            return (int)result;
        }

        /// <summary>
        /// Skips a given number of characters into a given Stream.
        /// </summary>
        /// <param name=" stream">The stream in which the skips are done.</param>
        /// <param name="number">The number of caracters to skip.</param>
        /// <returns>The number of characters skipped.</returns>
        public static long Skip(StreamReader stream, long number)
        {
            long skippedBytes = 0;
            for (long index = 0; index < number; index++)
            {
                stream.Read();
                skippedBytes++;
            }
            return skippedBytes;
        }

        /// <summary>
        /// Skips a given number of characters into a given StringReader.
        /// </summary>
        /// <param name="strReader">The StringReader in which the skips are done.</param>
        /// <param name="number">The number of caracters to skip.</param>
        /// <returns>The number of characters skipped.</returns>
        public static long Skip(StringReader strReader, long number)
        {
            long skippedBytes = 0;
            for (long index = 0; index < number; index++)
            {
                strReader.Read();
                skippedBytes++;
            }
            return skippedBytes;
        }


        /// <summary>
        /// Converts a string to an array of bytes
        /// </summary>
        /// <param name="sourceString">The string to be converted</param>
        /// <returns>The new array of bytes</returns>
        public static byte[] ToByteArray(String sourceString)
        {
            return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
        }
        
        /// <summary>
        /// Converts a array of object-type instances to a byte-type array.
        /// </summary>
        /// <param name="tempObjectArray">Array to convert.</param>
        /// <returns>An array of byte type elements.</returns>
        public static byte[] ToByteArray(Object[] tempObjectArray)
        {
            byte[] byteArray = null;
            if (tempObjectArray != null)
            {
                byteArray = new byte[tempObjectArray.Length];
                for (int index = 0; index < tempObjectArray.Length; index++)
                    byteArray[index] = (byte)tempObjectArray[index];
            }
            return byteArray;
        }

        
  }
}

   
    
  








Related examples in the same category

1.Use StreamWriter to create a text file
2.Reading from a text file line by line
3.Read data in line by line
4.StreamReader.ReadLine
5.Catch file read exception and retry
6.Construct StreamWriter from FileSream
7.Create a StreamWriter in UTF8 mode
8.StreamReader And Writer
9.illustrates reading and writing text dataillustrates reading and writing text data
10.Asynchronously reads a streamAsynchronously reads a stream
11.The use of a buffered stream to serve as intermediate data holder for another streamThe use of a buffered stream to serve as intermediate data holder for another stream
12.Demonstrates attaching a StreamReader object to a stream
13.Demonstrates attaching a StreamWriter object to a stream
14.A simple key-to-disk utility that demonstrates a StreamWriterA simple key-to-disk utility that 
   demonstrates a StreamWriter
15.Open a file using StreamWriterOpen a file using StreamWriter
16.A help program that uses a disk file to store help informationA help program that uses a disk file 
   to store help information
17.Try and catch exceptions for StreamWriter
18.Using StreamWriter 3
19.Reads a stream into a byte array.
20.Copies one stream into another.
21.Copy Stream from fromStream to toStream
22.Enumerate Lines for StreamReader
23.Enumerate non-empty Lines for StreamReader
24.Fifo Stream
25.Read from stream
26.Read from a Stream ensuring all the required data is read.
27.Serializes and object to a stream. It will flush and close the underlying stream.
28.Add OutputStream and InputStream to IDbCommand
29.Read Stream to End
30.Copy Stream and close
31.Stream Converter
32.Buffered InputStream
33.Page Filter Stream
34.Copies an Stream into another Stream.