Есть ли способ преобразовать System.IO.Stream в Windows.Storage.Streams.IRandomAccessStream? - PullRequest
52 голосов
/ 06 октября 2011

в Windows 8; Я хотел бы передать содержимое MemoryStream классу, который принимает параметр типа Windows.Storage.Streams.IRandomAccessStream. Есть ли способ преобразовать этот MemoryStream в IRandomAccessStream?

Ответы [ 7 ]

93 голосов
/ 13 октября 2011

Чтобы использовать расширения: необходимо добавить «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

Не будем говорить, что Microsoft не слушает сообщество разработчиков;)

В объявлении для .NET FX 4.5.1 Microsoft заявляет, что:

Многие из вас искали способ преобразования потока .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;

НТН.

7 голосов
/ 06 октября 2011

Нашли более элегантное решение:

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);
    }
}
5 голосов
/ 06 октября 2011

После некоторых экспериментов я обнаружил, что работает следующий код.

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 голосов
/ 28 июня 2013

В Windows 8 нет встроенного метода пути. Для Windows 8.1 мы добавили метод расширения Stream.AsRandomAccessStream ():

internal static IRandomAccessStream ToRandomAccessStream(byte[] array)
{
    MemoryStream stream = new MemoryStream(array);
    return stream.AsRandomAccessStream();
}
3 голосов
/ 12 марта 2013

Ничто из вышеперечисленного не работает для меня сегодня (возможно, некоторые изменения API, так как ответы были опубликованы). Единственный способ, который работает, это

IRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream();
using (var inputStream = stream.AsInputStream())
{
    await RandomAccessStream.CopyAsync(inputStream, inMemoryStream);
}
inMemoryStream.Seek(0);
0 голосов
/ 28 августа 2013

Посмотрите на эту ссылку:

Как преобразовать байтовый массив в IRandomAccessStream

В нем также приведены примеры и реализация конструктора байтового массива (и одиндля потоков .NET), полезно, если вы хотите использовать методы SetSource или SetSourceAsync класса BitmapImage (как в моем случае).

Надеюсь, это кому-нибудь поможет ...

0 голосов
/ 14 ноября 2011

Этот фрагмент кода превращает поток (stream) в InMemoryRandomAccessStream (ims), который реализует IRandomAccessStream. Хитрость в том, что CopyTo должен вызываться в фоновом потоке.

        InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream();
        var imsWriter = ims.OpenWrite();
        await Task.Factory.StartNew(() => stream.CopyTo(imsWriter));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...