是否有办法将System.IO.Stream转换为Windows.Storage.Streams.IRandomAcce

本文关键字:转换 Windows Storage IRandomAcce Streams Stream IO System 是否 | 更新日期: 2023-09-27 18:10:37

Windows 8;我想把内存流的内容传递给一个类,这个类接受Windows.Storage.Streams.IRandomAccessStream类型的参数。是否有任何方法将此内存流转换为IRandomAccessStream?

是否有办法将System.IO.Stream转换为Windows.Storage.Streams.IRandomAcce

要使用扩展名:必须添加"using System.IO"

在Windows8中,. net和WinRT类型通常在底层与兼容类型之间进行转换,所以你不必关心它。

然而,对于流,有一些辅助方法可以在WinRT和。net流之间进行转换:用于从WinRT流转换->net流:
InMemoryRandomAccessStream win8Stream = GetData(); // Get a data stream from somewhere.
System.IO.Stream inputStream = win8Stream.AsStream()

用于从。net流转换->WinRT流:

Windows.Storage.Streams.IInputStream inStream = stream.AsInputStream();
Windows.Storage.Streams.IOutputStream outStream = stream.AsOutputStream();

更新:2013-09-01

不要说微软不听取开发者社区的意见;)

在。net FX 4.5.1的公告中,微软声明:

你们中的许多人一直想要一种将。net流转换为Windows运行时IRandomAccessStream的方法。我们把它叫做AsRandomAccessStream扩展方法。我们没能在Windows 8中加入这个功能,但这是我们在Windows 8.1预览版中最先添加的功能之一。

您现在可以编写以下代码,使用HttpClient下载图像,将其加载到BitmapImage中,然后将其设置为Xaml image控件的源。

    //access image via networking i/o
    var imageUrl = "http://www.microsoft.com/global/en-us/news/publishingimages/logos/MSFT_logo_Web.jpg";
    var client = new HttpClient();
    Stream stream = await client.GetStreamAsync(imageUrl);
    var memStream = new MemoryStream();
    await stream.CopyToAsync(memStream);
    memStream.Position = 0;
    var bitmap = new BitmapImage();
    bitmap.SetSource(memStream.AsRandomAccessStream());
    image.Source = bitmap;

HTH .

找到了一个更优雅的解决方案:

public static class MicrosoftStreamExtensions
{
    public static IRandomAccessStream AsRandomAccessStream(this Stream stream)
    {
        return new RandomStream(stream);
    }
}
class RandomStream : IRandomAccessStream
{
    Stream internstream;
    public RandomStream(Stream underlyingstream)
    {
        internstream = underlyingstream;
    }
    public IInputStream GetInputStreamAt(ulong position)
    {
        //THANKS Microsoft! This is GREATLY appreciated!
        internstream.Position = (long)position;
        return internstream.AsInputStream();
    }
    public IOutputStream GetOutputStreamAt(ulong position)
    {
        internstream.Position = (long)position;
        return internstream.AsOutputStream();
    }
    public ulong Size
    {
        get
        {
            return (ulong)internstream.Length;
        }
        set
        {
            internstream.SetLength((long)value);
        }
    }
    public bool CanRead
    {
        get { return this.internstream.CanRead; }
    }
    public bool CanWrite
    {
        get { return this.internstream.CanWrite; }
    }
    public IRandomAccessStream CloneStream()
    {
        throw new NotSupportedException();
    }
    public ulong Position
    {
        get { return (ulong)this.internstream.Position; }
    }
    public void Seek(ulong position)
    {
        this.internstream.Seek((long)position, SeekOrigin.Begin);
    }
    public void Dispose()
    {
        this.internstream.Dispose();
    }
    public Windows.Foundation.IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
    {
        return this.GetInputStreamAt(this.Position).ReadAsync(buffer, count, options);
    }
    public Windows.Foundation.IAsyncOperation FlushAsync()
    {
        return this.GetOutputStreamAt(this.Position).FlushAsync();
    }
    public Windows.Foundation.IAsyncOperationWithProgress WriteAsync(IBuffer buffer)
    {
        return this.GetOutputStreamAt(this.Position).WriteAsync(buffer);
    }
}

经过一些实验,我发现下面的代码是工作的。

using System;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage.Streams;
partial class MainPage
{
    public MainPage()
    {
        var memoryStream = new MemoryStream(new byte[] { 65, 66, 67 });
        ConvertToRandomAccessStream(memoryStream, UseRandomAccessStream);
        InitializeComponent();
    }
    void UseRandomAccessStream(IRandomAccessStream stream)
    {
        var size = stream.Size;
    } // put breakpoint here to check size
    private static async void ConvertToRandomAccessStream(MemoryStream memoryStream,
         Action<IRandomAccessStream> callback)
    {
        var randomAccessStream = new InMemoryRandomAccessStream();
        var outputStream = randomAccessStream.GetOutputStreamAt(0);
        var dw = new DataWriter(outputStream);
        var task = new Task(() => dw.WriteBytes(memoryStream.ToArray()));
        task.Start();
        await task;
        await dw.StoreAsync();
        var success = await outputStream.FlushAsync();
        callback(randomAccessStream);
    }
}

UPDATE:我还尝试了更优雅的方法实现:

    private static void ConvertToRandomAccessStream(MemoryStream memoryStream,
        Action<IRandomAccessStream> callback)
    {
        var randomAccessStream = new InMemoryRandomAccessStream();
        var outputStream = randomAccessStream.GetOutputStreamAt(0);
        RandomAccessStream.Copy(memoryStream.AsInputStream(), outputStream);
        callback(randomAccessStream);
    }

奇怪的是,它不起作用。当我稍后调用stream.Size时,我得到0。

更新我改变了函数返回IRandomAccessStream而不是使用回调函数

public static async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream)
{
    var randomAccessStream = new InMemoryRandomAccessStream();
    var outputStream = randomAccessStream.GetOutputStreamAt(0);
    var dw = new DataWriter(outputStream);
    var task = new Task(() => dw.WriteBytes(memoryStream.ToArray()));
    task.Start();
    await task;
    await dw.StoreAsync();
    await outputStream.FlushAsync();
    return randomAccessStream;
}

Windows 8没有内置的way方法。对于Windows 8.1,我们增加了Stream.AsRandomAccessStream()扩展方法:

internal static IRandomAccessStream ToRandomAccessStream(byte[] array)
{
    MemoryStream stream = new MemoryStream(array);
    return stream.AsRandomAccessStream();
}

以上都不适合我今天(也许一些API的变化,因为答案张贴)。唯一有效的方法是

IRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream();
using (var inputStream = stream.AsInputStream())
{
    await RandomAccessStream.CopyAsync(inputStream, inMemoryStream);
}
inMemoryStream.Seek(0);

此代码片段将流(stream)转换为实现IRandomAccessStream的InMemoryRandomAccessStream (ims)。关键在于CopyTo必须在后台线程中调用。

        InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream();
        var imsWriter = ims.OpenWrite();
        await Task.Factory.StartNew(() => stream.CopyTo(imsWriter));

看看这个链接:

如何将字节数组转换为IRandomAccessStream

它还给出了一个字节数组构造函数的示例和实现(以及一个. net流),如果你想使用BitmapImage类的SetSourceSetSourceAsync方法(就像我的情况一样),它很有用。