如何:在 .NET Framework 和 Windows 运行时流之间进行转换(仅限 Windows)How to: Convert between .NET Framework and Windows Runtime streams (Windows only)

适用于 UWP 应用的 .NET Framework 是完整的 .NET Framework 的子集。The .NET Framework for UWP apps is a subset of the full .NET Framework. 由于 UWP 应用的安全性和其他要求,你无法使用整套 .NET Framework API 来打开和读取文件。Because of security and other requirements for UWP apps, you can't use the full set of .NET Framework APIs to open and read files. 有关详细信息,请参阅适用于 UWP 应用的 .NET 概述For more information, see .NET for UWP apps overview. 但是,你可能需要将 .NET Framework API 用于其他流处理操作。However, you may want to use .NET Framework APIs for other stream manipulation operations. 若要操作这些流,可以在 .NET Framework 流类型(如 MemoryStreamFileStream)和 Windows 运行时流(如 IInputStreamIOutputStreamIRandomAccessStream)之间进行转换。To manipulate these streams, you can convert between a .NET Framework stream type such as MemoryStream or FileStream, and a Windows Runtime stream such as IInputStream, IOutputStream, or IRandomAccessStream.

System.IO.WindowsRuntimeStreamExtensions 类包含简化这些转换的方法。The System.IO.WindowsRuntimeStreamExtensions class contains methods that make these conversions easy. 但是,.NET Framework 与 Windows 运行时流之间存在一些基本差异,这将影响使用这些方法所获得的结果,如以下部分中所述:However, underlying differences between .NET Framework and Windows Runtime streams affect the results of using these methods, as described in the following sections:

从 Windows 运行时流转换为 .NET Framework 流Convert from a Windows Runtime to a .NET Framework stream

若要从 Windows 运行时流转换为 .NET Framework 流,请使用以下 System.IO.WindowsRuntimeStreamExtensions 方法之一:To convert from a Windows Runtime stream to a .NET Framework stream, use one of the following System.IO.WindowsRuntimeStreamExtensions methods:

Windows 运行时提供支持只读、只写或读写的流类型。The Windows Runtime offers stream types that support reading only, writing only, or reading and writing. 如果将 Windows 运行时流转换为 .NET Framework 流,这些功能将保留。These capabilities are maintained when you convert a Windows Runtime stream to a .NET Framework stream. 此外,如果你在 Windows 运行时流与 .NET Framework 流之间转换,则将取回原始 Windows 运行时实例。Furthermore, if you convert a Windows Runtime stream to a .NET Framework stream and back, you get the original Windows Runtime instance back.

最佳做法是使用与要转换的 Windows 运行时流的功能匹配的转换方法。It’s best practice to use the conversion method that matches the capabilities of the Windows Runtime stream you want to convert. 但是,由于 IRandomAccessStream 是可读写的(它同时实现了 IOutputStreamIInputStream),因此转换方法将保留原始流的功能。However, since IRandomAccessStream is readable and writeable (it implements both IOutputStream and IInputStream), the conversion methods maintain the capabilities of the original stream. 例如,使用 WindowsRuntimeStreamExtensions.AsStreamForRead 转换 IRandomAccessStream 不会限制转换的 .NET Framework 流的可读性。For example, using WindowsRuntimeStreamExtensions.AsStreamForRead to convert an IRandomAccessStream doesn't limit the converted .NET Framework stream to being readable. 它也是可写的。It's also writable.

示例:将 Windows 运行时随机访问流转换为 .NET Framework 流Example: Convert Windows Runtime random-access to .NET Framework stream

若要从 Windows 运行时随机访问流转换为 .NET Framework 流,请使用 WindowsRuntimeStreamExtensions.AsStream 方法。To convert from a Windows Runtime random-access stream to a .NET Framework stream, use the WindowsRuntimeStreamExtensions.AsStream method.

下面的代码示例会提示用户选择文件,使用 Windows 运行时 API 将其打开,然后将其转换为 .NET Framework 流。The following code example prompts you to select a file, opens it with Windows Runtime APIs, and then converts it to a .NET Framework stream. 它可读取流,并将其输出为文本块。It reads the stream and outputs it to a text block. 在输出结果之前,通常使用 .NET Framework API 操作流。You would typically manipulate the stream with .NET Framework APIs before outputting the results.

若要运行此示例,请创建包含一个名为 TextBlock1 的文本块和一个名为 Button1 的按钮的 UWP XAML 应用。To run this example, create a UWP XAML app that contains a text block named TextBlock1 and a button named Button1. 将按钮单击事件与此示例中所示的 button1_Click 方法关联。Associate the button click event with the button1_Click method shown in the example.

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 运行时流Convert from a .NET Framework to a Windows Runtime stream

若要从.NET Framework 流转换为 Windows 运行时流,请使用下列任一 System.IO.WindowsRuntimeStreamExtensions 方法:To convert from a .NET Framework stream to a Windows Runtime stream, use one of the following System.IO.WindowsRuntimeStreamExtensions methods:

在将 .NET Framework 流转换为 Windows 运行时流时,转换后的流的功能将取决于原始流。When you convert a .NET Framework stream to a Windows Runtime stream, the capabilities of the converted stream depend on the original stream. 例如,如果原始流支持读取和写入,并且你调用 WindowsRuntimeStreamExtensions.AsInputStream 来转换流,则返回的类型为 IRandomAccessStreamFor example, if the original stream supports both reading and writing, and you call WindowsRuntimeStreamExtensions.AsInputStream to convert the stream, the returned type is an IRandomAccessStream. IRandomAccessStream 可实现 IInputStreamIOutputStream,且支持读取和写入。IRandomAccessStream implements IInputStream and IOutputStream, and supports reading and writing.

.NET Framework 流不支持克隆,即使转换后也是如此。.NET Framework streams don't support cloning, even after conversion. 如果将 .NET Framework 流转换为 Windows 运行时流,并调用 GetInputStreamAtGetOutputStreamAt(这会直接调用 CloneStreamCloneStream),则会引发异常。If you convert a .NET Framework stream to a Windows Runtime stream and call GetInputStreamAt or GetOutputStreamAt, which call CloneStream, or if you call CloneStream directly, an exception occurs.

示例:将 .NET Framework 转换为 Windows 运行时随机访问流Example: Convert .NET Framework to Windows Runtime random-access stream

要从 .NET Framework 流转换为 Windows 运行时随机访问流,请使用 AsRandomAccessStream 方法,如以下示例所示:To convert from a .NET Framework stream to a Windows Runtime random-access stream, use the AsRandomAccessStream method, as shown in the following example:

重要

确保所使用的 .NET Framework 流支持查找或将其复制到支持查找的流。Make sure that the .NET Framework stream you are using supports seeking, or copy it to a stream that does. 可使用 Stream.CanSeek 属性来确定这一点。You can use the Stream.CanSeek property to determine this.

若要运行此示例,请创建一个面向 .NET Framework 4.5.1 的且包含一个名为 TextBlock2 的文本块和一个名为 Button2的按钮的 UWP XAML 应用。To run this example, create a UWP XAML app that targets the .NET Framework 4.5.1 and contains a text block named TextBlock2 and a button named Button2. 将按钮单击事件与此示例中所示的 button2_Click 方法关联。Associate the button click event with the button2_Click method shown in the example.

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

请参阅See also