52 votes

Existe-t-il un moyen de convertir un System.IO.Stream en un Windows.Storage.Streams.IRandomAccessStream?

Sous Windows 8; Je souhaite transmettre le contenu d'un MemoryStream à une classe qui accepte un paramètre de type Windows.Storage.Streams.IRandomAccessStream. Est-il possible de convertir ce MemoryStream en un IRandomAccessStream?

94voto

Rich Turner Points 4845

Dans Windows8, .NET et WinRT types sont généralement converties ou de types compatibles sous le capot de sorte que vous n'avez pas à s'en soucier.

Pour les cours d'eau, cependant, il existe des méthodes d'aide à convertir entre WinRT et .NET flux: Pour la conversion de WinRT flux -> .NET flux:

InMemoryRandomAccessStream win8Stream = GetData(); // Get a data stream from somewhere.
System.IO.Stream inputStream = win8Stream.AsStream()

Pour la conversion de .NET flux -> WinRT flux:

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

Mise à JOUR: 2013-09-01

Qu'il ne soit pas dit que Microsoft ne veut pas écouter de la communauté des développeurs ;)

Dans l' annonce .NET FX 4.5.1, Microsoft indique que:

Beaucoup d'entre vous ont été de vouloir un moyen de convertir un .NET diffuser à un Windows Runtime IRandomAccessStream. Appelons ça un AsRandomAccessStream méthode d'extension. Nous n'avons pas pu obtenir cette fonctionnalité dans Windows 8, mais il a été un de nos premiers ajouts à Windows 8.1 Preview.

Vous pouvez maintenant écrire le code suivant, pour télécharger une image avec HttpClient, le charger dans un BitmapImage et alors définie comme la source d'une Xaml contrôle de l'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.

7voto

IDWMaster Points 2075

Trouvé une solution plus élégante:

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

5voto

Roman Boiko Points 2171

Après quelques expériences, j'ai trouvé que le code suivant fonctionnait.

 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: J'ai également essayé une méthode plus élégante:

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

Étrangement, ça ne marche pas. Quand j'appelle stream.Size plus tard, je reçois zéro.

UPDATE J'ai changé la fonction pour retourner le IRandomAccessStream plutôt que d'utiliser la fonction de rappel

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

4voto

Immo Landwerth Points 649

Il n'y a pas de méthode intégrée à Windows 8. Pour Windows 8.1, nous avons ajouté une méthode d'extension Stream.AsRandomAccessStream ():

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

3voto

Igor Kulman Points 6565

Aucune de ces solutions ne fonctionne pour moi aujourd'hui (peut-être quelques modifications de l'API depuis la publication des réponses). La seule façon qui fonctionne est

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X