Практическое руководство. Преобразование между потоками .NET Framework и потоками среды выполнения Windows (только в Windows)

.NET Framework для приложений UWP — это подмножество полной платформы .NET Framework. Из-за требований к безопасности и другим аспектам в приложениях UWP нельзя использовать полный набор API платформы .NET Framework для открытия и чтения файлов. Дополнительные сведения см. в статье Обзор .NET для приложений UWP. Однако может потребоваться использовать API платформы .NET Framework для других операций обработки потока. Для работы с потоками вы можете выполнить преобразование между типом потока .NET Framework, таким как MemoryStream или FileStream, и потоком среды выполнения Windows, таким как IInputStream, IOutputStream или IRandomAccessStream.

Класс System.IO.WindowsRuntimeStreamExtensions содержит методы, которые позволяют легко выполнить эти преобразования. Однако различия между потоками на платформе .NET Framework и в среде выполнения Windows влияют на результаты использования этих методов, как описано в следующих разделах:

Преобразование потока среды выполнения Windows в поток .NET Framework

Поток среды выполнения Windows можно преобразовать в поток .NET Framework, используя один из следующих методов System.IO.WindowsRuntimeStreamExtensions.

  • WindowsRuntimeStreamExtensions.AsStream преобразует поток случайного доступа в среде выполнения Windows в управляемый поток в .NET для приложений UWP.

  • WindowsRuntimeStreamExtensions.AsStreamForWrite преобразует поток вывода в среде выполнения Windows в управляемый поток в .NET для приложений UWP.

  • WindowsRuntimeStreamExtensions.AsStreamForRead преобразует входной поток в среде выполнения Windows в управляемый поток в .NET для приложений UWP.

Среда выполнения Windows предлагает типы потоков, которые поддерживают только чтение, только запись или чтение и запись. Эти возможности поддерживаются при преобразовании потока среды выполнения Windows в поток .NET Framework. Кроме того, при преобразовании потока среды выполнения Windows в поток .NET Framework и обратно можно получить исходный экземпляр среды выполнения Windows.

Рекомендуется использовать метод преобразования, соответствующий возможностям потока среды выполнения Windows, который необходимо преобразовать. Но поскольку поток IRandomAccessStream поддерживает чтение и запись (реализует как IOutputStream, так и IInputStream), любые методы преобразования позволяют сохранить возможности исходного потока. Например, использование WindowsRuntimeStreamExtensions.AsStreamForRead для преобразования IRandomAccessStream не ограничит возможности преобразованного потока .NET Framework только чтением. Он также доступен для записи.

Пример. Преобразование потока среды выполнения Windows с прямым доступом в поток .NET Framework

Для преобразования случайного потока доступа в среде выполнения Windows в поток .NET Framework используйте метод WindowsRuntimeStreamExtensions.AsStream.

В следующем примере кода вам будет предложено выбрать файл, он откроется с API среды выполнения Windows, а затем преобразуется в поток .NET Framework. Поток считывается и выводится в текстовый блок. Обычно вы работаете с потоком с помощью API .NET Framework, прежде чем вывести результаты.

Для выполнения этого примера создайте XAML-приложение UWP, которое содержит текстовый блок с именем TextBlock1 и кнопку с именем Button1. Свяжите событие нажатия кнопки с методом button1_Click, как показано в примере.

using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Storage;
using System.Net.Http;
using Windows.Storage.Pickers;

private async void button1_Click(object sender, RoutedEventArgs e)
{
    // Create a file picker.
    FileOpenPicker picker = new FileOpenPicker();

    // Set properties on the file picker such as start location and the type
    // of files to display.
    picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
    picker.ViewMode = PickerViewMode.List;
    picker.FileTypeFilter.Add(".txt");

    // Show picker enabling user to pick one file.
    StorageFile result = await picker.PickSingleFileAsync();

    if (result != null)
    {
        try
        {
            // Retrieve the stream. This method returns a IRandomAccessStreamWithContentType.
            var stream = await result.OpenReadAsync();

            // Convert the stream to a .NET stream using AsStream, pass to a
            // StreamReader and read the stream.
            using (StreamReader sr = new StreamReader(stream.AsStream()))
            {
                TextBlock1.Text = sr.ReadToEnd();
            }
        }
        catch (Exception ex)
        {
            TextBlock1.Text = "Error occurred reading the file. " + ex.Message;
        }
    }
    else
    {
        TextBlock1.Text = "User did not pick a file";
    }
}
Imports System.IO
Imports System.Runtime.InteropServices.WindowsRuntime
Imports Windows.UI.Xaml
Imports Windows.UI.Xaml.Controls
Imports Windows.UI.Xaml.Media.Imaging
Imports Windows.Storage
Imports System.Net.Http
Imports Windows.Storage.Pickers

Private Async Sub button1_Click(sender As Object, e As RoutedEventArgs)
    ' Create a file picker.
    Dim picker As New FileOpenPicker()

    ' Set properties on the file picker such as start location and the type of files to display.
    picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary
    picker.ViewMode = PickerViewMode.List
    picker.FileTypeFilter.Add(".txt")

    ' Show picker that enable user to pick one file.
    Dim result As StorageFile = Await picker.PickSingleFileAsync()

    If result IsNot Nothing Then
        Try
            ' Retrieve the stream. This method returns a IRandomAccessStreamWithContentType.
            Dim stream = Await result.OpenReadAsync()

            ' Convert the stream to a .NET stream using AsStreamForRead, pass to a 
            ' StreamReader and read the stream.
            Using sr As New StreamReader(stream.AsStream())
                TextBlock1.Text = sr.ReadToEnd()
            End Using
        Catch ex As Exception
            TextBlock1.Text = "Error occurred reading the file. " + ex.Message
        End Try
    Else
        TextBlock1.Text = "User did not pick a file"
    End If
End Sub

Преобразование потока .NET Framework в поток среды выполнения Windows

Чтобы преобразовать поток .NET Framework в поток в среде выполнения Windows, используйте один из следующих методов System.IO.WindowsRuntimeStreamExtensions.

  • WindowsRuntimeStreamExtensions.AsInputStream преобразует управляемый поток в .NET для приложений UWP во входной поток в среде выполнения Windows.

  • WindowsRuntimeStreamExtensions.AsOutputStream преобразует управляемый поток в .NET для приложений UWP в поток вывода в среде выполнения Windows.

  • WindowsRuntimeStreamExtensions.AsRandomAccessStream преобразует управляемый поток .NET для приложений UWP в поток с прямым доступом, который можно использовать для чтения и записи в среде выполнения Windows.

При преобразовании потока .NET Framework в поток среды выполнения Windows возможности преобразованного потока зависят от исходного потока. Например, если исходный поток поддерживает чтение и запись, можно вызвать метод WindowsRuntimeStreamExtensions.AsInputStream для преобразования потока, после чего будет возвращен тип IRandomAccessStream. IRandomAccessStream реализует IInputStream и IOutputStream и поддерживает чтение и запись.

Потоки .NET Framework не поддерживают клонирование даже после преобразования. В случае преобразования потока .NET Framework в поток среды выполнения Windows с последующим вызовом метода GetInputStreamAt или GetOutputStreamAt, который вызывает CloneStream, или при вызове CloneStream напрямую, возникнет исключение.

Пример. Преобразование потока .NET Framework в поток среды выполнения Windows с прямым доступом

Чтобы преобразовать поток .NET Framework в поток среды выполнения Windows с прямым доступом, используйте метод AsRandomAccessStream, как показано в следующем примере:

Важно!

Убедитесь, что используемый вами поток .NET Framework поддерживает поиск, или скопируйте его в поток, поддерживающий поиск. Чтобы это определить, используйте свойство Stream.CanSeek .

Для выполнения этого примера создайте XAML-приложение UWP, предназначенное для .NET Framework 4.5.1 и содержащее текстовый блок с именем TextBlock2 и кнопку с именем Button2. Свяжите событие нажатия кнопки с методом button2_Click, как показано в примере.

using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Storage;
using System.Net.Http;
using Windows.Storage.Pickers;

private async void button2_Click(object sender, RoutedEventArgs e)
{
    // Create an HttpClient and access an image as a stream.
    var client = new HttpClient();
    Stream stream = await client.GetStreamAsync("https://docs.microsoft.com/en-us/dotnet/images/hub/featured-1.png");
    // Create a .NET memory stream.
    var memStream = new MemoryStream();
    // Convert the stream to the memory stream, because a memory stream supports seeking.
    await stream.CopyToAsync(memStream);
    // Set the start position.
    memStream.Position = 0;
    // Create a new bitmap image.
    var bitmap = new BitmapImage();
    // Set the bitmap source to the stream, which is converted to a IRandomAccessStream.
    bitmap.SetSource(memStream.AsRandomAccessStream());
    // Set the image control source to the bitmap.
    image1.Source = bitmap;
}
Imports System.IO
Imports System.Runtime.InteropServices.WindowsRuntime
Imports Windows.UI.Xaml
Imports Windows.UI.Xaml.Controls
Imports Windows.UI.Xaml.Media.Imaging
Imports Windows.Storage
Imports System.Net.Http
Imports Windows.Storage.Pickers

Private Async Sub button2_Click(sender As Object, e As RoutedEventArgs)


    ' Create an HttpClient and access an image as a stream.
    Dim client = New HttpClient()
    Dim stream As Stream = Await client.GetStreamAsync("https://docs.microsoft.com/en-us/dotnet/images/hub/featured-1.png")
    ' Create a .NET memory stream.
    Dim memStream = New MemoryStream()

    ' Convert the stream to the memory stream, because a memory stream supports seeking.
    Await stream.CopyToAsync(memStream)

    ' Set the start position.
    memStream.Position = 0

    ' Create a new bitmap image.
    Dim bitmap = New BitmapImage()

    ' Set the bitmap source to the stream, which is converted to a IRandomAccessStream.
    bitmap.SetSource(memStream.AsRandomAccessStream())

    ' Set the image control source to the bitmap.
    image1.Source = bitmap
End Sub

См. также