C# 异步写入文件

C# 异步写入文件,c#,asp.net,asynchronous,C#,Asp.net,Asynchronous,是否有任何方法可以编写一个异步函数,该函数将数据反复写入文件 当我编写异步函数时,出现以下错误 进程无法访问文件“c:\Temp\Data.txt”,因为另一个进程正在使用该文件 public void GoButton_Click(object sender, System.EventArgs e) { IAsyncResult ar = DoSomethingAsync(strURL, strInput); Session["result"] = ar; Respon

是否有任何方法可以编写一个异步函数,该函数将数据反复写入文件

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

进程无法访问文件“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();
    }
}
public void GoButton_单击(对象发送者,System.EventArgs e)
{
IAsyncResult ar=DoSomethingAsync(strURL,strInput);
会话[“结果”]=ar;
重定向(“wait1.aspx”);
}
专用IAsyncResult DoSomethingAsync(字符串strURL,字符串strInput)
{
DoSomethingDelegate DoSomethingDelegate=新的DoSomethingDelegate(DoSomething);
IAsyncResult ar=doSomethingDelegate.BeginInvoke(strURL,strInput,new AsyncCallback(MyCallback),null);
返回ar;
}
私有委托void DoSomethingDelegate(字符串strURL、字符串strInput);
私有无效MyCallback(IAsyncResult ar)
{
AsyncResult aResult=(AsyncResult)ar;
DoSomethingDelegate DoSomethingDelegate=(DoSomethingDelegate)aResult.AsyncDelegate;
EndInvoke(ar);
}
专用空位尺寸(字符串strURL、字符串strInput)
{
int i=0;
对于(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();
}
}

异步写入文件无法解决此问题。您需要等待文件可用。

最终这取决于您为什么要尝试这样做

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


或者,如果你知道什么时候需要打开文件,什么时候需要关闭文件,你可以在需要的时候打开它,然后一直打开它进行写入,直到你知道不再需要它为止。

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

在下面的控制台示例中包括以下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发生在操作系统级别。在许多情况下,这将避免阻塞线程池线程。要启用此选项,必须在构造函数调用中指定UseAncy=true或options=FileOptions.Asynchronous参数

如果通过指定文件路径直接打开StreamReader和StreamWriter,则它们没有此选项。如果您向StreamReader/Writer提供一个由FileStream类打开的流,则StreamReader/Writer确实具有此选项。请注意,异步在UI应用程序中提供了响应优势,即使线程池线程被阻塞,因为UI线程在等待期间不会被阻塞

书写文本

以下示例将文本写入文件。在每个wait语句中,该方法立即退出。当文件I/O完成时,该方法将在WAIT语句之后的语句处恢复。注意,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中。与前面的示例不同,wait的求值产生一个值。ReadAsync方法返回一个任务,因此对wait的求值产生一个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();
    }
} 
static void Main(字符串[]args)
{
ProcessRead().Wait();
控制台。写入(“完成”);
Console.ReadKey();
}
静态异步任务ProcessRead()
{
字符串文件路径=@“c:\temp2\temp2.txt”;
if(File.Exists(filePath)==false)
{
WriteLine(“未找到文件:+filePath”);
}
否则{
试一试{
string text=await ReadTextAsync(文件路径);
控制台写入线(文本);
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
}
}
}
静态异步任务ReadTextAsync(字符串文件路径)
{
使用(FileStream sourceStream=newfilestream(filePath,
FileMode.Open,FileAccess.Read,FileShare.Read,
bufferSize:4096,UseAync:true)
{
StringBuilder sb=新的StringBuilder();
字节[]缓冲区=新字节[0x1000];
国际货币联盟;
while((numRead=wait sourceStream.ReadAsync(buffer,0,buffer.Length))!=0)
{
string text=Encoding.Unicode.GetString(缓冲区,0,numRead);
附加(正文);
}
使某人返回字符串();
}
} 
原来的消息来源是,但不幸的是,链接现在似乎已经死了


希望这有助于…

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

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

如果您使用一个简单的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();
    }
}

简单明了的解决方案:

using var file = new StreamWriter(path);
await file.WriteAsync(content);

是的,有可能。请确保您没有在主线程中打开文件,也没有使用其他线程进行修改。我应该在哪里修改代码?如果您打开流,则通常会发生异常。在给定的代码示例中,您只写入现有流,但创建流的代码(将引发异常)丢失。请查看是否在Visual Studio或记事本中打开了该文件?我正在为web服务进行某种负载测试。有时它从客户端返回“记录不存在”。我想重复这个问题。我应该在哪里修改代码以关闭和打开文件。你能和我分享一下吗?嗯,我不确定你是如何处理文件的(我是C#新手,我有VB背景),但我通常使用StreamWriter/streamreaders(也在C#中)。StreamWriter使用其构造函数方法打开文件,然后将其保持打开状态以便写入,直到调用close方法为止。所以每次你想写一些东西到一个文件,你可以做构造器
using var file = new StreamWriter(path);
await file.WriteAsync(content);