using System;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using System.Threading;
|
using System.Threading.Tasks;
|
|
namespace CommonUtil
|
{
|
/// <summary>
|
///
|
/// </summary>
|
public static partial class ExtendUtil
|
{
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="inStream"></param>
|
/// <param name="outStream"></param>
|
/// <returns></returns>
|
public static long WriteTo(this Stream inStream, Stream outStream)
|
{
|
if (inStream is MemoryStream memoryStream)
|
{
|
memoryStream.WriteTo(outStream);
|
return memoryStream.Position;
|
}
|
|
var data = new byte[4096];
|
long total = 0;
|
int bytesRead;
|
|
while ((bytesRead = inStream.Read(data, 0, data.Length)) > 0)
|
{
|
outStream.Write(data, 0, bytesRead);
|
total += bytesRead;
|
}
|
|
return total;
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <returns></returns>
|
public static IEnumerable<string> ReadLines(this Stream stream)
|
{
|
if (stream == null)
|
{
|
throw new ArgumentNullException(nameof(stream));
|
}
|
|
using (var reader = new StreamReader(stream))
|
{
|
string line;
|
while ((line = reader.ReadLine()) != null)
|
{
|
yield return line;
|
}
|
}
|
}
|
|
/// <summary>
|
/// @jonskeet: Collection of utility methods which operate on streams.
|
/// r285, February 26th 2009: http://www.yoda.arachsys.com/csharp/miscutil/
|
/// </summary>
|
public const int DefaultBufferSize = 8 * 1024;
|
|
/// <summary>
|
/// Copies all the data from one stream into another.
|
/// </summary>
|
public static long CopyTo(this Stream input, Stream output)
|
{
|
return CopyTo(input, output, DefaultBufferSize);
|
}
|
|
/// <summary>
|
/// Copies all the data from one stream into another, using a buffer
|
/// of the given size.
|
/// </summary>
|
public static long CopyTo(this Stream input, Stream output, int bufferSize)
|
{
|
if (bufferSize < 1)
|
{
|
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
}
|
|
return CopyTo(input, output, new byte[bufferSize]);
|
}
|
|
/// <summary>
|
/// Copies all the data from one stream into another, using the given
|
/// buffer for transferring data. Note that the current contents of
|
/// the buffer is ignored, so the buffer needn't be cleared beforehand.
|
/// </summary>
|
public static long CopyTo(this Stream input, Stream output, byte[] buffer)
|
{
|
if (buffer == null)
|
{
|
throw new ArgumentNullException(nameof(buffer));
|
}
|
|
if (input == null)
|
{
|
throw new ArgumentNullException(nameof(input));
|
}
|
|
if (output == null)
|
{
|
throw new ArgumentNullException(nameof(output));
|
}
|
|
if (buffer.Length == 0)
|
{
|
throw new ArgumentException("Buffer has length of 0");
|
}
|
|
long total = 0;
|
int read;
|
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
|
{
|
output.Write(buffer, 0, read);
|
total += read;
|
}
|
return total;
|
}
|
|
/// <summary>
|
/// Reads exactly the given number of bytes from the specified stream.
|
/// If the end of the stream is reached before the specified amount
|
/// of data is read, an exception is thrown.
|
/// </summary>
|
public static byte[] ReadExactly(this Stream input, int bytesToRead)
|
{
|
return ReadExactly(input, new byte[bytesToRead]);
|
}
|
|
/// <summary>
|
/// Reads into a buffer, filling it completely.
|
/// </summary>
|
public static byte[] ReadExactly(this Stream input, byte[] buffer)
|
{
|
return ReadExactly(input, buffer, buffer.Length);
|
}
|
|
/// <summary>
|
/// Reads exactly the given number of bytes from the specified stream,
|
/// into the given buffer, starting at position 0 of the array.
|
/// </summary>
|
public static byte[] ReadExactly(this Stream input, byte[] buffer, int bytesToRead)
|
{
|
return ReadExactly(input, buffer, 0, bytesToRead);
|
}
|
|
/// <summary>
|
/// Reads exactly the given number of bytes from the specified stream,
|
/// into the given buffer, starting at position 0 of the array.
|
/// </summary>
|
public static byte[] ReadExactly(this Stream input, byte[] buffer, int startIndex, int bytesToRead)
|
{
|
if (input == null)
|
{
|
throw new ArgumentNullException(nameof(input));
|
}
|
|
if (buffer == null)
|
{
|
throw new ArgumentNullException(nameof(buffer));
|
}
|
|
if (startIndex < 0 || startIndex >= buffer.Length)
|
{
|
throw new ArgumentOutOfRangeException(nameof(startIndex));
|
}
|
|
if (bytesToRead < 1 || startIndex + bytesToRead > buffer.Length)
|
{
|
throw new ArgumentOutOfRangeException(nameof(bytesToRead));
|
}
|
|
return ReadExactlyFast(input, buffer, startIndex, bytesToRead);
|
}
|
|
/// <summary>
|
/// Same as ReadExactly, but without the argument checks.
|
/// </summary>
|
private static byte[] ReadExactlyFast(Stream fromStream, byte[] intoBuffer, int startAtIndex, int bytesToRead)
|
{
|
var index = 0;
|
while (index < bytesToRead)
|
{
|
var read = fromStream.Read(intoBuffer, startAtIndex + index, bytesToRead - index);
|
if (read == 0)
|
{
|
throw new EndOfStreamException
|
($"End of stream reached with {bytesToRead - index} byte{(bytesToRead - index == 1 ? "s" : "")} left to read.");
|
}
|
|
index += read;
|
}
|
return intoBuffer;
|
}
|
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="bytes"></param>
|
/// <param name="withBytes"></param>
|
/// <returns></returns>
|
public static byte[] Combine(this byte[] bytes, params byte[][] withBytes)
|
{
|
var combinedLength = bytes.Length + withBytes.Sum(b => b.Length);
|
var to = new byte[combinedLength];
|
|
Buffer.BlockCopy(bytes, 0, to, 0, bytes.Length);
|
var pos = bytes.Length;
|
|
foreach (var b in withBytes)
|
{
|
Buffer.BlockCopy(b, 0, to, pos, b.Length);
|
pos += b.Length;
|
}
|
|
return to;
|
}
|
/// <summary>
|
///
|
/// </summary>
|
public static int AsyncBufferSize = 81920; // CopyToAsync() default value
|
|
/// <summary>
|
/// Returns bytes in publiclyVisible MemoryStream
|
/// </summary>
|
public static MemoryStream InMemoryStream(this byte[] bytes)
|
{
|
return new MemoryStream(bytes, 0, bytes.Length, writable: true, publiclyVisible: true);
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="ms"></param>
|
/// <returns></returns>
|
public static string ReadToEnd(this MemoryStream ms)
|
{
|
return ReadToEnd(ms, Encoding.UTF8);
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="ms"></param>
|
/// <param name="encoding"></param>
|
/// <returns></returns>
|
public static string ReadToEnd(this MemoryStream ms, Encoding encoding)
|
{
|
ms.Position = 0;
|
try
|
{
|
var ret = encoding.GetString(ms.GetBuffer(), 0, (int)ms.Length);
|
return ret;
|
}
|
catch (UnauthorizedAccessException)
|
{
|
using (var reader = new StreamReader(ms, encoding, true, DefaultBufferSize, leaveOpen: true))
|
{
|
return reader.ReadToEnd();
|
}
|
}
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="ms"></param>
|
/// <returns></returns>
|
public static byte[] GetBufferAsBytes(this MemoryStream ms)
|
{
|
try
|
{
|
return ms.GetBuffer();
|
}
|
catch (UnauthorizedAccessException)
|
{
|
return ms.ToArray();
|
}
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <returns></returns>
|
public static string ReadToEnd(this Stream stream)
|
{
|
return ReadToEnd(stream, Encoding.UTF8);
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <param name="encoding"></param>
|
/// <returns></returns>
|
public static string ReadToEnd(this Stream stream, Encoding encoding)
|
{
|
if (stream is MemoryStream ms)
|
{
|
return ms.ReadToEnd();
|
}
|
|
if (stream.CanSeek)
|
{
|
stream.Position = 0;
|
}
|
|
using (var reader = new StreamReader(stream, encoding, true, DefaultBufferSize, leaveOpen: true))
|
{
|
return reader.ReadToEnd();
|
}
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <returns></returns>
|
public static Task<string> ReadToEndAsync(this Stream stream)
|
{
|
return ReadToEndAsync(stream, Encoding.UTF8);
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <param name="encoding"></param>
|
/// <returns></returns>
|
public static Task<string> ReadToEndAsync(this Stream stream, Encoding encoding)
|
{
|
if (stream is MemoryStream ms)
|
{
|
return ms.ReadToEndAsync(encoding);
|
}
|
|
if (stream.CanSeek)
|
{
|
stream.Position = 0;
|
}
|
|
using (var reader = new StreamReader(stream, encoding, true, DefaultBufferSize, leaveOpen: true))
|
{
|
return reader.ReadToEndAsync();
|
}
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <param name="output"></param>
|
/// <param name="token"></param>
|
/// <returns></returns>
|
public static Task WriteToAsync(this MemoryStream stream, Stream output, CancellationToken token = default(CancellationToken))
|
{
|
return WriteToAsync(stream, output, Encoding.UTF8, token);
|
}
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="stream"></param>
|
/// <param name="output"></param>
|
/// <param name="encoding"></param>
|
/// <param name="token"></param>
|
/// <returns></returns>
|
public static async Task WriteToAsync(this MemoryStream stream, Stream output, Encoding encoding, CancellationToken token)
|
{
|
try
|
{
|
await output.WriteAsync(stream.GetBuffer(), 0, (int)stream.Length, token);
|
}
|
catch (UnauthorizedAccessException)
|
{
|
|
var bytes = stream.ToArray();
|
await output.WriteAsync(bytes, 0, bytes.Length, token);
|
}
|
}
|
}
|
}
|