web-dev-qa-db-fra.com

Comment async Files.ReadAllLines et attendre des résultats?

J'ai le code suivant,

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        button1.IsEnabled = false;

        var s = File.ReadAllLines("Words.txt").ToList(); // my WPF app hangs here
        // do something with s

        button1.IsEnabled = true;
    }

Words.txt a une tonne de mots que j'ai lus dans la variable s, j'essaie d'utiliser des mots clés async et await en C # 5 en utilisant Async CTP Library pour que l'application WPF ne se bloque pas. Jusqu'à présent, j'ai le code suivant,

    private async void button1_Click(object sender, RoutedEventArgs e)
    {
        button1.IsEnabled = false;

        Task<string[]> ws = Task.Factory.FromAsync<string[]>(
            // What do i have here? there are so many overloads
            ); // is this the right way to do?

        var s = await File.ReadAllLines("Words.txt").ToList();  // what more do i do here apart from having the await keyword?
        // do something with s

        button1.IsEnabled = true;
    }

L'objectif est de lire le fichier en mode asynchrone plutôt que synchronisé, afin d'éviter le blocage de l'application WPF.

Toute aide est la bienvenue, merci!

53
user677607

UPDATE: les versions asynchrones de File.ReadAll[Lines|Bytes|Text] , File.AppendAll[Lines|Text] et File.WriteAll[Lines|Bytes|Text] sont désormais fusionnées dans .NET Core . Nous espérons que ces méthodes seront de nouveau portées sur .NET Framework, Mono, etc. et intégrées dans une future version de .NET Standard.

Utilisation de Task.Run, qui est essentiellement un wrapper pour Task.Factory.StartNew, pour des wrappers asynchrones est une odeur de code

Si vous ne voulez pas gaspiller une unité centrale en utilisant une fonction de blocage, vous devez attendre une méthode IO vraiment asynchrone, StreamReader.ReadToEndAsync , comme ceci:

using (var reader = File.OpenText("Words.txt"))
{
    var fileText = await reader.ReadToEndAsync();
    // Do something with fileText...
}

Cela donnera le fichier entier en tant que string au lieu de List<string>. Si vous avez plutôt besoin de lignes, vous pouvez facilement séparer la chaîne par la suite, comme ceci:

using (var reader = File.OpenText("Words.txt"))
{
    var fileText = await reader.ReadToEndAsync();
    return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
}

EDIT: Voici quelques méthodes pour obtenir le même code que File.ReadAllLines, mais de manière vraiment asynchrone. Le code est basé sur l'implémentation de File.ReadAllLines lui-même:

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

public static class FileEx
{
    /// <summary>
    /// This is the same default buffer size as
    /// <see cref="StreamReader"/> and <see cref="FileStream"/>.
    /// </summary>
    private const int DefaultBufferSize = 4096;

    /// <summary>
    /// Indicates that
    /// 1. The file is to be used for asynchronous reading.
    /// 2. The file is to be accessed sequentially from beginning to end.
    /// </summary>
    private const FileOptions DefaultOptions = FileOptions.Asynchronous | FileOptions.SequentialScan;

    public static Task<string[]> ReadAllLinesAsync(string path)
    {
        return ReadAllLinesAsync(path, Encoding.UTF8);
    }

    public static async Task<string[]> ReadAllLinesAsync(string path, Encoding encoding)
    {
        var lines = new List<string>();

        // Open the FileStream with the same FileMode, FileAccess
        // and FileShare as a call to File.OpenText would've done.
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, DefaultOptions))
        using (var reader = new StreamReader(stream, encoding))
        {
            string line;
            while ((line = await reader.ReadLineAsync()) != null)
            {
                lines.Add(line);
            }
        }

        return lines.ToArray();
    }
}
107
khellang

Utilisez Stream.ReadAsync pour la lecture asynchrone du fichier, 

private async void Button_Click(object sender, RoutedEventArgs e)
{
    string filename = @"c:\Temp\userinputlog.txt";
    byte[] result;

    using (FileStream SourceStream = File.Open(filename, FileMode.Open))
    {
        result = new byte[SourceStream.Length];
        await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
    }

    UserInput.Text = System.Text.Encoding.ASCII.GetString(result);
}

Lire MSDN Stream.ReadAsync

0
Mak Ahmed