web-dev-qa-db-ja.com

非同期でファイルに書き込む

データをファイルに繰り返し書き込む非同期関数を作成する方法はありますか?.

非同期関数を作成すると、次のエラーが発生します

別のプロセスで使用されているため、プロセスはファイル 'c:\ Temp\Data.txt'にアクセスできません

public void GoButton_Click(object sender, System.EventArgs e)
{
    IAsyncResult ar = DoSomethingAsync(strURL, strInput);
    Session["result"] = ar;
    Response.Redirect("wait1.aspx");
}

private IAsyncResult DoSomethingAsync(string strURL, string strInput)
{
    DoSomethingDelegate doSomethingDelegate = new DoSomethingDelegate(DoSomething);
    IAsyncResult ar = doSomethingDelegate.BeginInvoke(strURL, strInput, new AsyncCallback(MyCallback), null);
    return ar;
}

private delegate void DoSomethingDelegate(string strURL, string strInput);

private void MyCallback(IAsyncResult ar)
{
    AsyncResult aResult = (AsyncResult)ar;
    DoSomethingDelegate doSomethingDelegate = (DoSomethingDelegate)aResult.AsyncDelegate;
    doSomethingDelegate.EndInvoke(ar);
}

private void DoSomething(string strURL, string strInput)
{
    int i = 0;
    for (i = 0; i < 1000; i++)
    {
        m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
        m_streamWriter.WriteLine("{0} ", MethodCall(strURL, strInput));
        m_streamWriter.Flush();
        m_streamWriter.Close();
    }
}
25
CPK_2011

まあ私は同じ問題を抱えていました。そして今それを解決しました。それはちょっと遅い提案ですが、他の人の助けになるかもしれません。

以下のコンソールの例に、次のusingステートメントを含めます。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
Use of the FileStream Class

以下の例では、FileStreamクラスを使用しています。このクラスには、オペレーティングシステムレベルで非同期I/Oを発生させるオプションがあります。多くの場合、これによりThreadPoolスレッドのブロックが回避されます。このオプションを有効にするには、コンストラクター呼び出しでuseAsync = trueまたはoptions = FileOptions.Asynchronous引数を指定する必要があります。

StreamReaderとStreamWriterには、ファイルパスを指定して直接開く場合、このオプションはありません。 StreamReader/Writerには、FileStreamクラスによって開かれたStreamを提供する場合、このオプションがあります。待機中はUIスレッドがブロックされないため、スレッドプールスレッドがブロックされている場合でも、非同期はUIアプリで応答性の利点を提供します。

テキストを書く

次の例では、テキストをファイルに書き込みます。各awaitステートメントで、メソッドはすぐに終了します。ファイルI/Oが完了すると、メソッドはawaitステートメントの次のステートメントから再開します。 async修飾子は、awaitステートメントを使用するメソッドの定義にあることに注意してください。

static void Main(string[] args)
{
    ProcessWrite().Wait();
    Console.Write("Done ");
    Console.ReadKey();
}

static Task ProcessWrite()
{
    string filePath = @"c:\temp2\temp2.txt";
    string text = "Hello World\r\n";

    return WriteTextAsync(filePath, text);
}

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

テキストを読む

次の例では、ファイルからテキストを読み取ります。テキストはバッファリングされ、この場合、StringBuilderに配置されます。前の例とは異なり、待機の評価により値が生成されます。 ReadAsyncメソッドはTaskを返すため、awaitの評価により、操作の完了後に返されるInt32値(numRead)が生成されます。

static void Main(string[] args)
{
    ProcessRead().Wait();
    Console.Write("Done ");
    Console.ReadKey();
}

static async Task ProcessRead()
{
    string filePath = @"c:\temp2\temp2.txt";

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

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

ファイルアクセスでの非同期の使用 から元のソースを見ることができます。

お役に立てば幸い...

26
curiousBoy

ファイルへの非同期書き込みを処理するヘルパーメソッドの例。

public async Task FileWriteAsync(string filePath, string messaage, bool append = true)
    {
        using (FileStream stream = new FileStream(filePath, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
        using (StreamWriter sw = new StreamWriter(stream))
        {
            await sw.WriteLineAsync(messaage);
        }
    }
10
SteveD

ファイルへの非同期書き込みはこの問題を解決しません。ファイルが利用可能になるまで待つ必要があります。

5
Erno

最終的には、それを実行しようとしている理由によって異なります。

ファイルに大量のデータを書き込む予定がない場合は、常にファイルを開いたり閉じたりできます。

または、ファイルを開くタイミングと閉じるタイミングがわかっている場合は、必要なときにファイルを開いて、不要になった時点まで書き込み用に開いたままにすることができます。

0
Pharap