【问题标题】:Is there a way to convert a System.IO.Stream to a Windows.Storage.Streams.IRandomAccessStream?有没有办法将 System.IO.Stream 转换为 Windows.Storage.Streams.IRandomAccessStream?
【发布时间】:2011-10-06 00:46:54
【问题描述】:

在 Windows 8 中;我想将 MemoryStream 的内容传递给接受 Windows.Storage.Streams.IRandomAccessStream 类型参数的类。有没有办法将此 MemoryStream 转换为 IRandomAccessStream?

【问题讨论】:

  • 没有扩展方法之类的.AsBuffer之类的吗?

标签: c# .net windows windows-8


【解决方案1】:

要使用扩展:您必须添加“使用 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

不要说微软不听它的开发者社区;)

announcement for .NET FX 4.5.1 中,微软声明:

你们中的许多人一直想要一种将 .NET 流转换为 Windows 运行时 IRandomAccessStream 的方法。让我们称之为 AsRandomAccessStream 扩展方法。我们无法将此功能添加到 Windows 8 中,但它是我们首次添加到 Windows 8.1 Preview 中的功能之一。

您现在可以编写以下代码,使用 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。

【讨论】:

  • 要使用这些扩展方法,您需要“使用 System.IO”。
  • 这应该是答案。这非常简单。使用扩展方法将 WinRT 流转换为 .Net 流。
  • 嗯,第一个被剪断的代码无法编译,但我明白了。
  • 感谢您的来信。固定。
  • 更新了选择的答案——这是最新的,并且提供了一种比预发布版本更优雅的方法。
【解决方案2】:

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

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);
    }
}

【讨论】:

  • 非常好。我正在从 Microsoft 寻找这样的包装器,但没有成功。
  • 这个解决方案有两个问题。 1)如果有人调用GetInputStreamAt(0),那么GetOutputStreamAt(1),输入流的位置也将更改为1。 2) 它接受任何流,所以CanSeek 属性可能等于false。在这种情况下,NotSupportedException 将被抛出。复制流对于大流来说效率较低,但不应该有这些问题。
  • @RomanBoiko 诚然,它不是任何类型流的通用解决方案,但它适用于许多类型的应用程序,这些应用程序仍将使用新类型的流,就好像它是旧方法一样(例如,只是从流中读取数据并将其传递给 WinRT 组件,然后摆脱 IRandomAccessStream。我还应该指出,IRandomAccessStream 不打算用作 System.IO.Stream,反之亦然,但这适用于当您想像使用 Stream 一样使用 IRandomAccessStream 时。
  • 当您确切地知道没有人会同时调用GetInputStreamAt(someNumber)GetOutputStreamAt(otherNumber) 并在同一时间段内同时使用它们时,这是一个很好且简单的解决方案。它可以通过存储Position 已更改的标志并在以后更改时抛出来扩展以防止此类情况。不过,仍然可能会出现一些错误......我强调的问题涉及违反IRandomAccessStream 的合同,尽管尚未记录。
  • @RomanBoiko 微软似乎对 Windows 8 的文档质量很差,代码示例很少,还有很多 TBD(待定)
【解决方案3】:

经过一些实验,我发现以下代码可以正常工作。

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);
    }
}

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

    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 时,我得到了零。

更新我将函数更改为返回 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;
}

【讨论】:

    【解决方案4】:

    在 Windows 8 上没有内置方式方法。对于 Windows 8.1,我们添加了 Stream.AsRandomAccessStream() 扩展方法:

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

    【讨论】:

      【解决方案5】:

      以上所有方法今天都不适合我(可能在发布答案后发生了一些 API 更改)。唯一可行的方法是

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

      【讨论】:

        【解决方案6】:

        此代码 sn-p 将流 (stream) 转换为实现 IRandomAccessStream 的 InMemoryRandomAccessStream (ims)。诀窍是必须在后台线程上调用 CopyTo。

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

        【讨论】:

        • 最后一行的任务位用:await stream.CopyToAsync(imsWriter);
        • InMemoryRandomAccessStream.OpenWrite() 似乎不存在了?
        • @JayBorseth 为什么?根据MSDN,确实存在。
        【解决方案7】:

        看看这个链接:

        How To Convert Byte Array To IRandomAccessStream

        它还提供了字节数组构造函数的示例和实现(以及用于 .NET 流的构造函数),如果您想使用 BitmapImage 类的 SetSourceSetSourceAsync 方法(如我的例子),这很有用.

        希望这对某人有所帮助...

        【讨论】:

          猜你喜欢
          • 2014-11-06
          • 2017-03-25
          • 2021-09-01
          • 2021-05-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多