Есть ли способ, чтобы преобразовать систему.ИО.Поток в окна.Место хранения.Потоки.IRandomAccessStream?
в Windows 8; я хотел бы передать содержимое MemoryStream в класс, который принимает параметр типа Windows.Место хранения.Потоки.Аргумент объект irandomaccessstream. Есть ли способ преобразовать этот поток памяти в IRandomAccessStream?
7 ответов:
чтобы использовать расширения: вы должны добавить "using System.IO"
в Windows8 типы .NET и WinRT обычно преобразуются в/из совместимых типов под капотом, поэтому вам не нужно заботиться об этом.
для потоков, однако, есть вспомогательные методы для преобразования между WinRT и .NET потоков: Для преобразования из WinRT streams - > .NET streams:
InMemoryRandomAccessStream win8Stream = GetData(); // Get a data stream from somewhere. System.IO.Stream inputStream = win8Stream.AsStream()
для преобразования из потоков .NET - > WinRT streams:
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;
НТН.
нашел более элегантное решение:
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); } }
обновление: Я также попробовал более элегантный метод реализации:
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; }
в Windows 8 нет встроенного метода way. Для Windows 8.1 мы добавили поток.Метод расширения 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
) в InMemoryRandomAccessStream (ims
), которые реализуютIRandomAccessStream
. Хитрость заключается в том, что CopyTo должен быть вызван в фоновом потоке.InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream(); var imsWriter = ims.OpenWrite(); await Task.Factory.StartNew(() => stream.CopyTo(imsWriter));
взгляните на эту ссылку:
Как Преобразовать Массив Байтов В IRandomAccessStream
Он также дает примеры и реализацию конструктора массива байтов (и один для потоков .NET), полезно, если вы хотите использовать
SetSource
илиSetSourceAsync
способыBitmapImage
класса (как в моем случае).надеюсь, это кому-то поможет...