Arlodotexe / OwlCore.Storage

The most flexible file system abstraction, ever. Built in partnership with the UWP Community.
15 stars 4 forks source link

Add progress reporting where appropriate #54

Open Arlodotexe opened 2 weeks ago

Arlodotexe commented 2 weeks ago

Progress reporting is a good call out. Generally the library is built so that progress reporting can be implemented application-side during an operation (e.g. navigating directories, moving things around, stream transfers). However, there's a few long-running extension methods where we could consider an IProgress parameter, such as Copy and Move.

Here is the inbox implementation for copying a file into a folder. Presumably, dotnet should supply us with an overload that takes an IProgress in Stream.CopyToAsync, but that doesn't appear to be the case. We'd need to build this ourselves or use one of the many versions that others have built.

Originally posted by @Arlodotexe in https://github.com/Arlodotexe/OwlCore.Storage/issues/12#issuecomment-2160903901

itsWindows11 commented 1 week ago

ChatGPT proposes this:

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public async Task CopyStreamWithProgressAsync(
    Stream source, 
    Stream destination, 
    IProgress<double> progress = null, 
    CancellationToken cancellationToken = default)
{
    const int bufferSize = 81920; // 80 KB buffer
    byte[] buffer = new byte[bufferSize];
    long totalBytesRead = 0;
    long totalLength = source.Length;

    int bytesRead;
    while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
    {
        await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);
        totalBytesRead += bytesRead;

        if (progress != null && totalLength > 0)
        {
            double percentage = (double)totalBytesRead / totalLength * 100;
            progress.Report(percentage);
        }
    }
}

Though we need to report the total bytes read along with the length instead of the percentage, and leave the rest for the implementor to decide what they want to do with the progress, and use ArrayPool. No idea if some underlying stream implementations will require special handling here.

Arlodotexe commented 5 days ago

Yeah, we should look at what others have already brainstormed online on sites like StackOverflow. Figuring out exactly what <T> to use for IProgress<T> isn't straightforward.