2012-08-02 98 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); 
     } 
    }