В Windows 8; Я хотел бы передать содержимое MemoryStream классу, который принимает параметр типа Windows.Storage.Streams.IRandomAccessStream. Есть ли способ конвертировать этот MemoryStream в IRandomAccessStream?
Есть ли способ конвертировать System.IO.Stream в Windows.Storage.Streams.IRandomAccessStream?
Ответ 1
Чтобы использовать расширения: вы должны добавить "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 Runtime 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;
НТН.
Ответ 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);
}
}
Ответ 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);
}
}
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
позже, я получаю нуль.
UPDATE Я изменил функцию, чтобы вернуть 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
Этот фрагмент кода превращает поток (stream
) в InMemoryRandomAccessStream (ims
), который реализует IRandomAccessStream
. Фокус в том, что CopyTo нужно вызвать в фоновом потоке.
InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream();
var imsWriter = ims.OpenWrite();
await Task.Factory.StartNew(() => stream.CopyTo(imsWriter));
Ответ 7
Взгляните на эту ссылку:
Как преобразовать байт-массив в IRandomAccessStream
Он также дает примеры и реализацию конструктора байтового массива (и одного для потоков .NET), полезно, если вы хотите использовать методы SetSource
или SetSourceAsync
класса BitmapImage
(как в моем случае).
Надеюсь, это поможет кому-то...