Search code examples
c#windows-runtimeuwpstoragefile

Can I get file.OpenStreamForReadAsync() from file.OpenStreamForWriteAsync()?


I am still learning the tricks of read/write file streams and hope someone could help if what I am looking for is feasible.

The code below makes WebApi calls (note GetAsync() on line 2) to get an image file Id and save downloaded file to database with computed Md5Hash. The code works fine, but in the interest of efficiency I was wondering if it's possible to get file.OpenStreamForReadAsync() from file.OpenStreamForWriteAsync() (not sure even if this is possible, but I can see some extension methods that operate on a stream but no luck with attempts I've made so far). If this is possible, I can avoid saving a file and opening it again, by instead making the GetMD5Hash() method call within the using (var fileStream = await file.OpenStreamForWriteAsync()){ ... } block.

Can I have the equivalent of Utils.GetMD5Hash(stream);, shown below outside the using block, inside the block, the intention being to avoid opening the file outside of the using block?

var client = new HttpClient();
var response = await client.GetAsync(new Uri($"{url}{imageId}")); // call to WebApi; url and imageId defined earlier

if (response.IsSuccessStatusCode)
{
    using (var contentStream = await response.Content.ReadAsInputStreamAsync())
    {
        var stream = contentStream.AsStreamForRead();
        var file = await imagesFolder.CreateFileAsync(imageFileName, CreationCollisionOption.ReplaceExisting);
        using (var fileStream = await file.OpenStreamForWriteAsync())
        {
            await stream.CopyToAsync(fileStream, 4096);

            // >>>> At this point, from the Write fileStream, can I get the equivalent of file.OpenStreamForReadAsync() ??

        }

        var stream = await file.OpenStreamForReadAsync();
        string md5Hash = await Utils.GetMD5Hash(stream);
        await AddImageToDataBase(file, md5Hash);
    }
}

Solution

  • A MemoryStream is read/write, so if all you wanted to do was to compute the hash, something like this should do the trick:

    var stream = contentStream.AsStreamForRead();
    using (var ms = new MemoryStream())
    {
        stream.CopyTo(ms);
        ms.Seek(0, SeekOrigin.Begin);
        string md5Hash = await Utils.GetMD5Hash(ms);
    }
    

    But since you want to save the file anyway (it's passed to AddImageToDataBase, after all), consider

    • Save to the MemoryStream
    • Reset the memory stream
    • Copy the memory stream to the file stream
    • Reset the memory stream
    • Compute the hash

    I'd suggest you do performance measurements, though. The OS does cache file I/O, so it's unlikely that you'd actually have to do a physical disk read to compute the hash. The performance gains might not be what you imagine.