29

有什么方法可以编写一个异步函数,将数据重复写入文件。

编写异步函数时出现以下错误

该进程无法访问文件“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();
    }
}
4

7 回答 7

29

那么我有同样的问题。现在解决了。这是一种迟到的建议,但可能对其他人有所帮助。

在下面的控制台示例中包含以下 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 中。与前面的示例不同,await 的评估产生一个值。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();
    }
} 

原始来源在这里,但不幸的是链接现在似乎已经死了。

希望有帮助...

于 2014-03-24T18:36:11.910 回答
15

处理异步写入文件的辅助方法示例。

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);
        }
    }
于 2017-05-22T16:11:01.823 回答
6

异步写入文件不会解决这个问题。您需要等待文件可用。

于 2012-08-02T09:41:26.390 回答
1

如果你使用一个简单的 StreamWriter,你可以用一个简单的类来替换它。不需要异步/等待。这是一个编写文本文件的示例。

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;

class LogWriter : IDisposable
{
    private BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
    private StreamWriter log = null;
    bool run = true;
    Task task = null;

    public LogWriter(string logFilePath)
    {
        log = new StreamWriter(logFilePath);
        task = Task.Run(() =>
        {
            while (run)
            {
                log.WriteLine(blockingCollection.Take());
            }
           });
    }

    public void WriteLine(string value)
    {
        blockingCollection.Add(value);
    }

    public void Dispose()
    {
        run = false;
        task.Dispose();
        log.Close();
        log.Dispose();
    }
}

要使用它,就像使用 StreamWriter 一样:

using (var log = new LogWriter(logFileName))
{
    log.WriteLine("Hello world");
    // Code here that should not be blocked by writing to the file
}
于 2020-09-11T07:24:22.877 回答
1

接受的答案具有常见的异步陷阱 - 缓冲区不会异步刷新。看看这个:https ://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#always-call-flushasync-on-streamwriters-or-streams-before-calling-dispose

在处理之前使用新的await using或手动刷新缓冲区

await using (var file = new StreamWriter(path)) //mind the "await using"
{
    await file.WriteAsync(content);
}

或者

using (var streamWriter = new StreamWriter(context.Response.Body))
{
    await streamWriter.WriteAsync("Hello World");
    await streamWriter.FlushAsync();
}
于 2021-09-26T19:57:07.167 回答
0

最终,这取决于你为什么要这样做。

如果您不打算向文件写入太多数据,则可以不断打开和关闭它。

或者,如果您知道文件何时打开以及何时关闭,您可以在需要时打开它,然后保持打开状态以进行写入,直到您知道不再需要它为止。

于 2012-08-02T09:51:20.857 回答
0

简单直接的解决方案:

using var file = new StreamWriter(path);
await file.WriteAsync(content);
于 2021-01-21T12:14:15.277 回答