Skip to content

Instantly share code, notes, and snippets.

@joncloud
Created August 11, 2020 16:18
Show Gist options
  • Save joncloud/400685b9501203e89abe26277e2d7333 to your computer and use it in GitHub Desktop.
Save joncloud/400685b9501203e89abe26277e2d7333 to your computer and use it in GitHub Desktop.
Tracking stream progress
using Azure.Storage.Blobs;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
BlobContainerClient container = default;
BlobClient blob = container.GetBlobClient("foo");
var properties = await blob.GetPropertiesAsync();
using var fileStream = File.Create("./blob");
using var progressStream = new ProgressStream(fileStream);
progressStream.BytesRead += read =>
{
var percentage = read / (float)properties.Value.ContentLength;
};
await blob.DownloadToAsync(progressStream);
}
}
class ProgressStream : Stream
{
readonly Stream _inner;
public ProgressStream(Stream inner) =>
_inner = inner;
public override bool CanRead => _inner.CanRead;
public override bool CanSeek => _inner.CanSeek;
public override bool CanWrite => _inner.CanWrite;
public override long Length => _inner.Length;
public override long Position
{
get => _inner.Position;
set => _inner.Position = value;
}
public override void Flush() => _inner.Flush();
public override Task FlushAsync(CancellationToken cancellationToken) => _inner.FlushAsync(cancellationToken);
public event Action<int> BytesRead;
protected virtual void OnBytesRead(int read)
{
if (read < 1) return;
BytesRead?.Invoke(read);
}
public override int Read(byte[] buffer, int offset, int count)
{
var read = _inner.Read(buffer, offset, count);
OnBytesRead(read);
return read;
}
public override int Read(Span<byte> buffer)
{
var read = _inner.Read(buffer);
OnBytesRead(read);
return read;
}
public override int ReadByte()
{
var value = _inner.ReadByte();
if (value > -1)
{
OnBytesRead(1);
}
return value;
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var read = await _inner.ReadAsync(buffer, offset, count, cancellationToken);
OnBytesRead(read);
return read;
}
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
var read = await _inner.ReadAsync(buffer, cancellationToken);
OnBytesRead(read);
return read;
}
public override long Seek(long offset, SeekOrigin origin) =>
_inner.Seek(offset, origin);
public override void SetLength(long value) =>
_inner.SetLength(value);
public event Action<int> BytesWritten;
protected virtual void OnBytesWritten(int written)
{
if (written < 1) return;
BytesWritten?.Invoke(written);
}
public override void Write(byte[] buffer, int offset, int count)
{
_inner.Write(buffer, offset, count);
OnBytesWritten(count);
}
public override void Write(ReadOnlySpan<byte> buffer)
{
_inner.Write(buffer);
OnBytesWritten(buffer.Length);
}
public override void WriteByte(byte value)
{
_inner.WriteByte(value);
OnBytesWritten(1);
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
await _inner.WriteAsync(buffer, offset, count, cancellationToken);
OnBytesWritten(count);
}
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
await _inner.WriteAsync(buffer, cancellationToken);
OnBytesWritten(buffer.Length);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment