Ich habe den folgenden Code,
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
hat eine Menge Wörter, die ich in die Variable s eingelesen habe. Ich versuche, async
und await
-Schlüsselwörter in C # 5 zu verwenden, wobei Async CTP Library
verwendet wird, damit die WPF-App nicht hängen bleibt. Bisher habe ich den folgenden Code,
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;
}
Das Ziel ist, die Datei asynchron und nicht synchron zu lesen, um ein Einfrieren der WPF-App zu vermeiden.
Jede Hilfe wird geschätzt, danke!
UPDATE: Async-Versionen von File.ReadAll[Lines|Bytes|Text]
, File.AppendAll[Lines|Text]
und File.WriteAll[Lines|Bytes|Text]
wurden jetzt in .NET Core zusammengeführt . Diese Methoden werden hoffentlich auf .NET Framework, Mono usw. portiert und in eine zukünftige Version von .NET Standard übernommen.
Verwenden von Task.Run
, das im Wesentlichen ein Wrapper für Task.Factory.StartNew
ist, für asynchrone Wrapper ist ein Codegeruch .
Wenn Sie einen CPU-Thread nicht durch Verwendung einer Blockierungsfunktion verschwenden möchten, sollten Sie auf eine wirklich asynchrone Methode IO StreamReader.ReadToEndAsync
wie folgt warten:
using (var reader = File.OpenText("Words.txt"))
{
var fileText = await reader.ReadToEndAsync();
// Do something with fileText...
}
Dadurch wird die gesamte Datei als string
anstelle von List<string>
abgerufen. Wenn Sie stattdessen Linien benötigen, können Sie die Zeichenfolge anschließend einfach aufteilen:
using (var reader = File.OpenText("Words.txt"))
{
var fileText = await reader.ReadToEndAsync();
return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
}
EDIT: Hier sind einige Methoden, um denselben Code wie File.ReadAllLines
zu erreichen, jedoch auf wirklich asynchrone Weise. Der Code basiert auf der Implementierung von File.ReadAllLines
selbst:
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();
}
}
Verwenden Sie Stream.ReadAsync zum asynchronen Lesen der Datei.
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);
}