Usar Async en acceso a archivos (C# y Visual Basic)

Puede utilizar la característica de Asincronía para tener acceso a archivos. Utilizando la característica de async, puede llamar a métodos asincrónicos sin usar devoluciones o dividir el código a través de varios métodos o de expresiones lambda. Para crear sincrónico codificar asincrónico, simplemente llama a un método asincrónico en lugar de un método sincrónico y agrega algunas palabras clave al código.

Puede considerar las siguientes razones de agregar asynchrony a las llamadas de acceso a archivos:

  • Asynchrony crea aplicaciones de interfaz de usuario más receptivas porque el subproceso de la interfaz de usuario que inicia la operación puede realizar otro trabajo. Si el subproceso de la interfaz de usuario debe ejecutar código que tarda mucho tiempo (por ejemplo, más de 50 milisegundos), la interfaz de usuario puede inmovilizar hasta que se complete la E/S y el subproceso de la interfaz de usuario puede procesar de nuevo entrada de teclado y mouse y otros eventos.

  • Asynchrony mejora la escalabilidad de ASP.NET y otras aplicaciones basadas en servidor reduce la necesidad de subprocesos. Si la aplicación utiliza un subproceso dedicado por respuesta y mil solicitudes se manejando simultáneamente, mil subprocesos necesarios. Las operaciones asincrónicas no tienen a menudo utilizar un subproceso durante la espera. Utilizan el subproceso existente de finalización de E/S brevemente en el extremo.

  • La latencia de una operación de acceso a archivos puede ser condiciones actuales inferior muy poco marcadas, pero la latencia puede aumentar considerablemente en el futuro. Por ejemplo, un archivo se puede mover a un servidor que está a través del mundo.

  • La sobrecarga adicional de utilizar la característica Async es pequeña.

  • Las tareas asincrónicas se pueden fácilmente ejecutar en paralelo.

Ejecutar los ejemplos

Nota

Los ejemplos de este tema no se aplica a las aplicaciones de Tienda Windows , que son aplicaciones de Windows 8 que son de plena pantalla y adecuadas para la interacción de toque.Para obtener información sobre cómo utilizar acceso a archivos async en aplicaciones de Tienda Windows , vea Información general de .NET para aplicaciones de la Tienda Windows y E/S de archivos y secuencias.Para obtener ejemplos de E/S de archivos para las aplicaciones de Tienda Windows , puede descargar Ejemplo de acceso a archivos.

Para ejecutar los ejemplos de este tema, puede crear Aplicación WPF o Aplicación de Windows Forms y agregar Botón. En el evento de Click button, agregue una llamada al primer método en cada ejemplo.

En los ejemplos siguientes, incluya Imports siguiente (Visual Basic) o los extractos de using (C#).

Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

Uso de la clase de la secuencia de archivo

Los ejemplos de este tema utilizan la clase de FileStream , que tiene una opción que haga E/S asincrónica aparezca en la ejecución de nivel de sistema. Con esta opción, puede evitar que un subproceso ThreadPool en muchos casos. Para habilitar esta opción, se especifica el argumento de useAsync=true o de options=FileOptions.Asynchronous en la llamada al constructor.

No puede usar esta opción con StreamReader y StreamWriter si abre ellos directamente especificando una ruta de acceso. Sin embargo, puede utilizar esta opción si se les proporciona Stream que abra la clase de FileStream . Observe que las llamadas asincrónicas son más rápidas en aplicaciones de interfaz de usuario incluso si un subproceso ThreadPool está bloqueado, porque el subproceso de la interfaz de usuario no se bloquea durante la espera.

Escritura de texto

Escribe el siguiente ejemplo texto en un archivo. En cada espera el fragmento, los resultados del método inmediatamente. Cuando se completa la E/S de archivos, los curriculums next del fragmento que sigue el fragmento de aguardar. Observe que el modificador async está en la definición de los métodos que utilizan el fragmento de aguardar.

Public Async Sub ProcessWrite()
    Dim filePath = "temp2.txt" 
    Dim text = "Hello World" & ControlChars.CrLf

    Await WriteTextAsync(filePath, text)
End Sub 

Private Async Function WriteTextAsync(filePath As String, text As String) As Task
    Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

    Using sourceStream As New FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize:=4096, useAsync:=True)

        Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
    End Using 
End Function
public async void ProcessWrite()
{
    string filePath = @"temp2.txt";
    string text = "Hello World\r\n";

    await WriteTextAsync(filePath, text);
}

private async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize: 4096, useAsync: true))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    };
}

El ejemplo original tiene el fragmento await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);, que es una contracción de los dos extractos siguientes:

Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
await theTask;

El primer fragmento devuelve una tarea y hace que el procesamiento del archivo al principio. El segundo fragmento con el aguardar hace que el método inmediatamente a la salida y devuelve otra tarea. Cuando el procesamiento del archivo completa más adelante, la ejecución vuelve al extraer que sigue el aguardar. Para obtener más información, vea Flujo de control en programas asincrónicos (C# y Visual Basic) y Tutorial: Usar el depurador con métodos asincrónicos.

Leer el texto

En el siguiente ejemplo se lee texto de un archivo. El texto se almacena en búfer y, en este caso, se coloca en StringBuilder. A diferencia del ejemplo anterior, la evaluación de aguardar genera un valor. El método de ReadAsync devuelve Task<Int32>, por lo que la evaluación de aguardar genera un valor de Int32 (numRead) después de que se complete la operación. Para obtener más información, vea Tipos de valor devuelto de Async (C y Visual Basic).

Public Async Sub ProcessRead()
    Dim filePath = "temp2.txt" 

    If File.Exists(filePath) = False Then
        Debug.WriteLine("file not found: " & filePath)
    Else 
        Try 
            Dim text As String = Await ReadTextAsync(filePath)
            Debug.WriteLine(text)
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try 
    End If 
End Sub 

Private Async Function ReadTextAsync(filePath As String) As Task(Of String)

    Using sourceStream As New FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize:=4096, useAsync:=True)

        Dim sb As New StringBuilder

        Dim buffer As Byte() = New Byte(&H1000) {}
        Dim numRead As Integer
        numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        While numRead <> 0
            Dim text As String = Encoding.Unicode.GetString(buffer, 0, numRead)
            sb.Append(text)

            numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        End While 

        Return sb.ToString
    End Using 
End Function
public async void ProcessRead()
{
    string filePath = @"temp2.txt";

    if (File.Exists(filePath) == false)
    {
        Debug.WriteLine("file not found: " + filePath);
    }
    else
    {
        try
        {
            string text = await ReadTextAsync(filePath);
            Debug.WriteLine(text);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
}

private async Task<string> ReadTextAsync(string filePath)
{
    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize: 4096, useAsync: true))
    {
        StringBuilder sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
}

E/S asincrónica paralela

El ejemplo siguiente muestra el procesamiento paralelo escribiendo 10 archivos de texto. Para cada archivo, el método de WriteAsync devuelve una tarea que se agregue a una lista de tareas. Los resultados del fragmento de await Task.WhenAll(tasks); el método y los curriculums next dentro del método cuando el procesamiento del archivo se completa para todas las tareas.

El ejemplo cierre todas las instancias de FileStream en un bloque de finally una vez completadas las tareas. Si cada FileStream en su lugar se creó en un fragmento de using , FileStream podría ser dispuesto antes de que la tarea se completa.

Tenga en cuenta que cualquier mejora del rendimiento es casi totalmente del procesamiento paralelo y no el procesamiento asincrónico. Las ventajas de asynchrony son que no implica varios subprocesos, y que no implica el subproceso de la interfaz de usuario.

Public Async Sub ProcessWriteMult()
    Dim folder = "tempfolder\" 
    Dim tasks As New List(Of Task)
    Dim sourceStreams As New List(Of FileStream)

    Try 
        For index = 1 To 10
            Dim text = "In file " & index.ToString & ControlChars.CrLf

            Dim fileName = "thefile" & index.ToString("00") & ".txt" 
            Dim filePath = folder & fileName

            Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

            Dim sourceStream As New FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize:=4096, useAsync:=True)

            Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
            sourceStreams.Add(sourceStream)

            tasks.Add(theTask)
        Next

        Await Task.WhenAll(tasks)
    Finally 
        For Each sourceStream As FileStream In sourceStreams
            sourceStream.Close()
        Next 
    End Try 
End Sub
public async void ProcessWriteMult()
{
    string folder = @"tempfolder\";
    List<Task> tasks = new List<Task>();
    List<FileStream> sourceStreams = new List<FileStream>();

    try
    {
        for (int index = 1; index <= 10; index++)
        {
            string text = "In file " + index.ToString() + "\r\n";

            string fileName = "thefile" + index.ToString("00") + ".txt";
            string filePath = folder + fileName;

            byte[] encodedText = Encoding.Unicode.GetBytes(text);

            FileStream sourceStream = new FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

            Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
            sourceStreams.Add(sourceStream);

            tasks.Add(theTask);
        }

        await Task.WhenAll(tasks);
    }

    finally
    {
        foreach (FileStream sourceStream in sourceStreams)
        {
            sourceStream.Close();
        }
    }
}

Al utilizar los métodos de WriteAsync y de ReadAsync , puede especificar CancellationToken, que puede usar para cancelar el centro de la ejecución de la operación. Para obtener más información, vea Ajustar una aplicación asincrónica (C# y Visual Basic) y Cancelación en subprocesos administrados.

Vea también

Tareas

Tutorial: Usar el depurador con métodos asincrónicos

Conceptos

Programación asincrónica con Async y Await (C# y Visual Basic)

Tipos de valor devuelto de Async (C y Visual Basic)

Flujo de control en programas asincrónicos (C# y Visual Basic)