2012-08-02 156 views
8

是否有任何方法可以编写一个将数据重复写入文件的异步函数。异步写入文件

我收到以下错误,当我写异步函数

该进程无法访问文件:因为它正在被另一个进程使用

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

是的,这是可能的。确保您不要在主线程中打开文件,也不要使用其他文件进行修改。 – Leri 2012-08-02 09:41:48

+0

我应该在哪里修改代码 – 2012-08-02 09:49:00

+0

如果您打开一个流,通常会发生异常。在给定的代码示例中,您只写入现有的流,但是创建流的代码(以及抛出的异常)缺失。 – Oliver 2012-08-02 09:49:40

回答

11

那么我有同样的问题。现在解决它。这有点晚,但可能会对其他人有所帮助。

在下面的控制台示例中包含以下使用语句。

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,则StreamReader/Writer具有此选项。请注意,即使线程池线程被阻塞,异步仍可在UI应用程序中提供响应优势,因为UI线程在等待期间未被阻止。

书写文字

以下示例将文本写入文件。在每个等待声明中,该方法立即退出。当文件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方法返回一个任务,这样的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(); 
    } 
} 

您可以从Using Async for File Access

希望去看一下原始来源这有助于...

+0

尽管此链接可能会回答问题,但最好在此处包含答案的重要部分,并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 – StarsSky 2014-03-24 18:56:48

+1

@StarsSky:你说得对,这完全合理。我将编辑它。感谢您的建议 – curiousBoy 2014-03-24 18:57:38

+3

答案现在有解决方案。 – curiousBoy 2014-03-24 19:03:14

4

“C \ TEMP \ DATA.TXT”异步写入文件不会解决此问题。您需要等待文件可用。

0

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

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

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

+0

我正在做一些Web服务的负载测试。有时它会从客户端返回“记录不存在”。我想重现这个问题。我应该在哪里修改代码来关闭和打开文件。你可以和我分享一下吗? – 2012-08-02 09:56:42

+0

嗯,我不知道你是如何处理文件(我是C#的新手,我来自VB背景),但我通常使用streamwriters/streamreaders(它也在C#中)。 Streamwriters用它们的构造函数方法打开文件,然后保持打开状态直到写入close方法。所以每次你想写一些东西到一个文件,你可以做构造函数,写作方法,然后是结束方法。正如我之前所说,不知道你想达到什么目的,我不能去推荐您。 你是否因为某种原因不断更新文件? (例如游戏) – Pharap 2012-08-02 10:07:44

+0

我正在重复访问web服务,有时会从客户端抛出“记录不存在”。我想从异端重现问题。 vb.net也适合我。这是某种Web方法调用的负载测试。多次和异步调用方法是我想要实现的。 – 2012-08-02 10:25:39

3

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

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