using System; using System.IO; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Tools { public static class ExStreamTools { public static void CopyTo(this Stream input, Stream output, int buffersize, long bytes) { byte[] buffer = new byte[buffersize]; int count; while (bytes > 0L && (count = input.Read(buffer, 0, (int)Math.Min((long)buffer.Length, bytes))) > 0) { output.Write(buffer, 0, count); bytes -= (long)count; } } public static async Task CopyToAsync(this Stream input, Stream output, int buffersize, long bytes, CancellationToken token =default) { byte[] buffer = new byte[buffersize]; int count; while (bytes > 0L && (count = await input.ReadAsync(buffer, 0, (int)Math.Min((long)buffer.Length, bytes), token)) > 0) { await output.WriteAsync(buffer, 0, count, token); bytes -= (long)count; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteValueUnmanaged(this Stream s, T t) where T : unmanaged { byte[] buffer = new byte[sizeof(T)]; fixed (byte* ptr = buffer) { *(T*)ptr = t; } s.Write(buffer, 0, buffer.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Task WriteValueUnmanagedAsync(this Stream s, T t, CancellationToken token = default) where T : unmanaged { byte[] buffer = new byte[sizeof(T)]; fixed (byte* ptr = buffer) { *(T*)ptr = t; } return s.WriteAsync(buffer, 0, buffer.Length, token); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteAll(this Stream s, byte[] buffer) { s.Write(buffer, 0, buffer.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task WriteAllAsync(this Stream s, byte[] buffer, CancellationToken token=default) { return s.WriteAsync(buffer, 0, buffer.Length,token); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ReadAll(this Stream s, byte[] buffer) { return s.Read(buffer, 0, buffer.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task ReadAllAsync(this Stream s, byte[] buffer, CancellationToken token = default) { return s.ReadAsync(buffer, 0, buffer.Length, token); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ReadAllBlocking(this Stream s, byte[] buffer) { return s.BlockingRead(buffer, 0, buffer.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task ReadAllBlockingAsync(this Stream s, byte[] buffer, CancellationToken token = default) { return s.BlockingReadAsync(buffer, 0, buffer.Length, token); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] ReadNew(this Stream s, int len) { byte[] buffer = new byte[len]; s.Read(buffer, 0, len); return buffer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task ReadNewAsync(this Stream s, int len, CancellationToken token = default) { byte[] buffer = new byte[len]; await s.ReadAsync(buffer, 0, len, token); return buffer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] ReadNewBlocking(this Stream s, int len) { byte[] buffer = new byte[len]; s.BlockingRead(buffer, 0, len); return buffer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task ReadNewBlockingAsync(this Stream s, int len, CancellationToken token = default) { byte[] buffer = new byte[len]; await s.BlockingReadAsync(buffer, 0, len, token); return buffer; } public static int BlockingRead(this Stream s, byte[] buffer, int offset, int count) { int read; int rlen = 0; while ((rlen += (read = s.Read(buffer, offset + rlen, count - rlen))) < count) if (read <= 0) break; return rlen; } public static async Task BlockingReadAsync(this Stream s, byte[] buffer, int offset, int count, CancellationToken token=default) { int read; int rlen = 0; while ((rlen += (read = await s.ReadAsync(buffer, offset + rlen, count - rlen, token))) < count) if (read <= 0) break; return rlen; } public static void WriteString(this Stream s, string str, Encoding encoding = null) { if (encoding == null) encoding = Encoding.UTF8; int code = encoding.CodePage; byte[] buf = encoding.GetBytes(str); s.WriteValueUnmanaged(buf.Length); s.WriteValueUnmanaged(code); s.WriteAll(buf); } public static Task WriteStringAsync(this Stream s, string str, CancellationToken token = default) => WriteStringAsync(s, str, Encoding.UTF8, token); public static async Task WriteStringAsync(this Stream s, string str, Encoding encoding, CancellationToken token=default) { int code = encoding.CodePage; byte[] buf = encoding.GetBytes(str); await s.WriteValueUnmanagedAsync(buf.Length, token); await s.WriteValueUnmanagedAsync(code,token); await s.WriteAllAsync(buf,token); } public static string ReadString(this Stream s, Encoding encoding = null) { int len = s.ReadValueUnmanaged(); int code = s.ReadValueUnmanaged(); byte[] buf = s.ReadNew(len); if (encoding == null) encoding = Encoding.GetEncoding(code); return encoding.GetString(buf); } public static async Task ReadStringAsync(this Stream s, CancellationToken token = default) { int len = await s.ReadValueUnmanagedAsync(token); int code = await s.ReadValueUnmanagedAsync(token); byte[] buf = await s.ReadNewAsync(len, token); var encoding = Encoding.GetEncoding(code); return encoding.GetString(buf); } public static async Task ReadStringAsync(this Stream s, Encoding encoding, CancellationToken token = default) { int len = await s.ReadValueUnmanagedAsync(token); await s.ReadValueUnmanagedAsync(token); byte[] buf = await s.ReadNewAsync(len, token); return encoding.GetString(buf); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe T ReadValueUnmanaged(this Stream s) where T : unmanaged { T output; byte[] buffer = new byte[sizeof(T)]; s.Read(buffer, 0, buffer.Length); fixed (byte* ptr = buffer) { output = *(T*)ptr; } return output; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task ReadValueUnmanagedAsync(this Stream s, CancellationToken token=default) where T : unmanaged { T output; int len; unsafe { len = sizeof(T); } byte[] buffer = new byte[len]; await s.ReadAsync(buffer, 0, buffer.Length, token); unsafe { fixed (byte* ptr = buffer) { output = *(T*)ptr; } } return output; } } }