ProgramingTip

Files.ReadAllLines를 비 동기화하고 결과를 찾는 방법은 무엇입니까?

bestdevel 2020. 12. 4. 19:48
반응형

Files.ReadAllLines를 비 동기화하고 결과를 찾는 방법은 무엇입니까?


다음 코드가 있습니다.

    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내가들로 읽은 단어 변수가 너무 많아서 WPF 앱이 멈추지 않도록 C # 5에서 asyncawait키워드를 사용하려고합니다 Async CTP Library. 지금까지 다음 코드가 있습니다.

    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;
    }

목표는 WPF 앱이 중단되는 것을 방지하기 위해 동기화가 아닌 것으로 파일을 읽는 것입니다.

어떤 도움을 주시면 감사하겠습니다!


UPDATE : 최신 버전 , 그리고 지금은 한 .NET 코어에 통합 및 .NET 코어 2.0과 함께 제공됩니다. .NET Standard 2.1에도 포함되어 있습니다.File.ReadAll[Lines|Bytes|Text]File.AppendAll[Lines|Text]File.WriteAll[Lines|Bytes|Text]

사용 Task.Run자체로의 래퍼 인 Task.Factory.StartNew랩퍼 것은 코드 냄새입니다 .

차단 기능을 사용하여 CPU를 사용하지 않고 다음과 같이 진정한 의미의 IO 메소드를 기다려야합니다 .StreamReader.ReadToEndAsync

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

이것은 전체 파일을 얻는 string대신의 List<string>. 대신 줄이 필요하면 다음과 같이 나중에 쉽게 쉽게 분할 할 수 있습니다.

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

편집 : 다음은 동일한 코드를 달성하는 몇 가지 방법 File.ReadAllLines이지만 진정한 의미 방식입니다. 코드는 자체 구현을 기반으로합니다 .File.ReadAllLines

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();
    }
}

파일의 읽기를 위해 Stream.ReadAsync를 사용합니다.

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);
}

MSDN Stream.ReadAsync 읽기


귀하의 질문에 설명 된 문제도 발생했습니다. 이전 답변에서 간단하게 해결했습니다.

string[] values;
StorageFolder folder = ApplicationData.Current.LocalFolder; // Put your location here.
IList<string> lines = await FileIO.ReadLinesAsync(await folder.GetFileAsync("Words.txt"););
lines.CopyTo(values, 0);

이 시도 :

private async void button1_Click(object sender, RoutedEventArgs e)
{
    button1.IsEnabled = false;
    try
    {
        var s = await Task.Run(() => File.ReadAllLines("Words.txt").ToList());
        // do something with s
    }
    finally
    {
        button1.IsEnabled = true;
    }
}

편집하다 :

이것이 작동하기 위해 try-finally가 필요하지 않습니다. 실제로 변경해야하는 단 한 줄입니다. 작동 방식을 설명하려면 : 이것은 다른 스레드를 생성하고 (실제로 스레드 풀에서 하나를 가져옴) 해당 스레드가 파일을 읽도록합니다. 파일 읽기가 끝나면 button1_Click 메서드의 나머지 부분이 결과와 함께 (GUI 스레드에서) 호출됩니다. 이것은 아마도 가장 효율적인 솔루션은 아니지만 GUI를 차단하지 않는 가장 간단한 코드 변경 일 것입니다.

참고 URL : https://stackoverflow.com/questions/13167934/how-to-async-files-readalllines-and-await-for-results

반응형