#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
{
///
/// Utility class that provides methods to manipulate stream of data.
///
///
/// This class is ported from Jakarta Commons IO 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:
/// http://www.developerfusion.co.uk/show/4696/
///
public sealed class StreamUtils
{
/// The name says it all.
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 {
output[outputOffset + i] = input[i];
}
}
/// Copy bytes from a [] to an Output .
/// the byte array to read from
///
/// the Output to write to
///
/// if an I/O problem occurs
public static void Copy(byte[] input, Stream output)
{
if (input.Length == 0) return;
output.Write(input, 0, input.Length);
}
///
/// Copy and convert bytes from a [] to chars on a
/// .
///
/// the byte array to read from
/// the to write to
/// in the case of an I/O problem
public static void Copy(byte[] input, StreamWriter outputWriter)
{
MemoryStream inputStream = new MemoryStream(input);
Copy(inputStream, outputWriter);
}
///
/// Copy and convert bytes from a [] to chars on a
/// .
///
///
///
///
public static void Copy(byte[] input, StreamWriter outputWriter, string encoding)
{
MemoryStream inputStream = new MemoryStream(input);
Copy(inputStream, outputWriter, encoding);
}
/// Copy the entire content from an Input to an Output .
/// the Input to read from the beginning of the stream
///
/// the Output to write to
///
/// the number of bytes copied
///
/// if an I/O problem occurs
public static int Copy(Stream input, Stream output)
{
return Copy(input, output, false);
}
/// Copy bytes from an Input to an Output .
/// the Input to read from
///
/// the Output to write to
///
/// 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.
///
/// the number of bytes copied
///
/// if an I/O problem occurs
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
// ----------------------------------------------------------------
/// Copy chars from a to a .
/// the to read from
///
/// the to write to
///
/// the number of characters copied
///
/// if an I/O problem occurs
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
// ----------------------------------------------------------------
/// Copy and convert bytes from an Input to chars on a
/// .
/// The platform's default encoding is used for the byte-to-char conversion.
///
/// the Input to read from
///
/// the to write to
///
/// if an I/O problem occurs
public static int Copy(Stream inputStream, StreamWriter outputStreamWriter)
{
StreamReader inputStreamReader = new StreamReader(inputStream, System.Text.Encoding.Default);
return Copy(inputStreamReader, outputStreamWriter);
}
///
/// Copy and convert bytes from an Input to chars on a
/// , using the specified encoding.
///
///
///
/// The name of a supported character encoding. See the
/// IANA
/// Charset Registry and MSDN: Encoding class
/// for a list of valid encoding types.
/// an I/O problem occurs
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
// ----------------------------------------------------------------
///
/// Serialize chars from a to bytes on an
/// Output , and flush the Output .
///
/// the to read from
/// the to write to
/// an I/O problem occurs
public static void Copy(StreamReader inputReader, Stream output)
{
StreamWriter outputWriter = new StreamWriter(output, System.Text.Encoding.Default);
Copy(inputReader, outputWriter);
outputWriter.Flush();
}
// ----------------------------------------------------------------
// String -> OutputStream
// ----------------------------------------------------------------
/// Serialize chars from a to bytes on an
/// Output , and
/// flush the Output .
///
/// the to read from
///
/// the Output to write to
///
/// an I/O problem occurs
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
// ----------------------------------------------------------------
/// Copy chars from a to a .
/// the to read from
///
/// the to write to
///
/// an I/O problem occurs
public static void Copy(String input, StreamWriter output)
{
output.Write(input);
}
///
/// Copy the exact number of bytes from the source to a
/// target .
///
/// Source to copy from
/// Target to copy to
/// number of bytes to copy
/// if the source stream does not have enough data.
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;
}
}
///
/// Reads data into a complete array, throwing an EndOfStreamException
/// if the stream runs out of data first, or if an IOException
/// naturally occurs.
///
/// The stream to read data from
/// The array to read bytes into. The array
/// will be completely filled from the stream, so an appropriate
/// size must be given.
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;
}
}
///
/// Reads data from the beginning of a stream until the end is reached. The
/// data is returned as a byte array.
///
/// The stream to read data from
/// thrown if any of the underlying IO calls fail
/// 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.
///
/// Note:
/// This method of reading the stream is not terribly efficient.
///
///
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);
}
}
}
///
/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array.
///
/// The stream to read data from
/// The initial buffer length. If the length is < 1,
/// then the default value of will be used.
///
/// thrown if any of the underlying IO calls fail
/// Use this method to get the data if you know the expected length of data to start with.
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;
}
///
/// Return an ASCII string from a stream of data
///
///
///
public static string GetAsciiString(Stream stream)
{
ASCIIEncoding encoding = new ASCIIEncoding();
return GetString(stream, encoding);
}
///
/// Return an UTF8 encoded string from a stream of data
///
///
///
public static string GetString(Stream stream)
{
UTF8Encoding encoding = new UTF8Encoding();
return GetString(stream, encoding);
}
///
/// Return a string from a stream. The string is returned with
/// the encoding provided.
///
///
///
///
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);
}
///
/// 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.
///
/// Source stream to read from
/// Target byte array to write to
/// offset index in the target
/// offset position in the stream
/// number of bytes to read in the stream
/// thrown if the target byte array is too small to stored
/// the required number of bytes read from the stream.
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;
}
}
///
/// Read a partial segment of a stream, starting from an offset position.
///
/// Source stream to read from
/// the starting offset position in the stream. Set to 0 if the stream is to be read from the beginning.
/// number of bytes to read
/// return partial segment as an array of bytes.
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;
}
///
/// Read a stream (like a file or HttpWebRequest) and write to another stream
///
/// the stream to read
/// the stream to write to
[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();
}
///
/// Try to skip bytes in the input stream and return the actual number of bytes skipped.
///
/// Input stream that will be used to skip the bytes
/// Number of bytes to be skipped
/// Actual number of bytes skipped
public static int Skip(Stream stream, int skipBytes)
{
long oldPosition = stream.Position;
long result = stream.Seek(skipBytes, SeekOrigin.Current) - oldPosition;
return (int)result;
}
///
/// Skips a given number of characters into a given Stream.
///
/// The stream in which the skips are done.
/// The number of caracters to skip.
/// The number of characters skipped.
public static long Skip(StreamReader stream, long number)
{
long skippedBytes = 0;
for (long index = 0; index < number; index++)
{
stream.Read();
skippedBytes++;
}
return skippedBytes;
}
///
/// Skips a given number of characters into a given StringReader.
///
/// The StringReader in which the skips are done.
/// The number of caracters to skip.
/// The number of characters skipped.
public static long Skip(StringReader strReader, long number)
{
long skippedBytes = 0;
for (long index = 0; index < number; index++)
{
strReader.Read();
skippedBytes++;
}
return skippedBytes;
}
///
/// Converts a string to an array of bytes
///
/// The string to be converted
/// The new array of bytes
public static byte[] ToByteArray(String sourceString)
{
return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
}
///
/// Converts a array of object-type instances to a byte-type array.
///
/// Array to convert.
/// An array of byte type elements.
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;
}
}
}