2012-02-22 51 views
0

我有一個腳本可以在多個線程上創建文件。偶爾,我會在document.SaveAs以下錯誤()調用:文檔文件將無法正常保存

{「Word無法保存或創建此文件確保硬盤,您 要保存文件上不充分,寫保護,或已損壞\ r (C:\ ... \ fileName.docx)。「}

這是鬱悶,因爲它似乎發生有時,而不是別人。我一直在花費最後一天的時間來解決問題,而且進展甚微。我排除的一件事是可能有多個線程試圖創建相同的文件。我確信這不會發生。在我的代碼中是否存在任何會導致這種情況的錯誤,或者這只是使用com對象時的一個事實?我正在做什麼代碼教程在那裏說,也許我應該放棄使用多線程?

BuildDocumentsThread(){ 
     var word = new Microsoft.Office.Interop.Word.Application(); 
     word.Options.CreateBackup = false; 
     var wordQuit = (Microsoft.Office.Interop.Word._Application)word; 

     foreach(var value in values){ 
      FormBuilder.BuildSummaryForm(word, value); 
     } 

     wordQuit.Quit(); 
} 

public static void BuildSummaryForm(Application word, string value) { 
     var summaryFormPath = Utilities.GetSummaryFilePath(value); 

     if (File.Exists(summaryFormPath)) 
      File.Delete(summaryFormPath); 

     object path = summaryFormPath; 
     object readOnly = false; 
     object o = System.Reflection.Missing.Value; 

     var document = word.Documents.Add(ref o, ref o, ref o, ref o); 
     document.Activate(); 

     Paragraph p1 = document.Content.Paragraphs.Add(ref o); 
     p1.Range.Font.Name = "Arial"; 
     p1.Range.Font.Size = 10; 
     p1.Range.Text = value; 

     document.SaveAs(ref path, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o); 
     document.Close(); 
} 
+0

SaveAs方法不是線程安全的(http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.documentclass.saveas(v = office.11​​)的.aspx)。另外,如果文件正在被另一個進程保存或打開,您可能會遇到此錯誤。 – 2012-02-22 15:26:49

+0

我必須問的第一件事:你在運行這個應用程序時沒有打開MS Word嗎? – ardnew 2012-02-22 15:26:55

+0

@JohnKoerner,由於不是線程安全的,這是否意味着它不應該與多個線程一起使用?我不明白頁面的含義:「任何公共靜態(在Visual Basic中爲Shared)成員都是線程安全的。」另外,我知道只有一個線程一次訪問單個文件。 – sooprise 2012-02-22 15:28:20

回答

1

如果SaveAs不是線程安全的,如John Koerner在註釋中所描述的那樣,您可以嘗試鎖定SaveAs和Close。

在這種情況下,我確信多線程過程將會非常有用,但這是最糟糕的嘗試。至少你會知道你的錯誤是否來自SaveAs函數。


要添加一些infromation您的評論如下:

添加一個類變量來創建鎖

private static object _savelock = new object(); 

然後在你的工人:

lock(_savelock) 
{ 
    document.SaveAs(ref path, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o); 
} 
document.Close(); 

在這種情況下,不會同時進行保存操作。鎖定關閉,以及可能需要

  • 1挑線鎖,並做保存
  • 在此期間2線程嘗試做一個保存,但等到前一個線程完成保存和釋放鎖

在這種情況下,您並不在乎它是否是相同的單詞實例。在這兩種情況下它都可以工作。

主要缺點是,如果保存操作佔用線程時間的95%,則多線程變得幾乎無用,因爲通過鎖定保存操作,只有5%的進程確實是多線程的。但是,如果「釋放」用戶界面並讓用戶在運行過程中繼續工作是目標,那麼這是一個可行的解決方案。

檢查http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx的鎖pricinple

+0

你能幫我理解嗎?假設我只使用一個單詞實例,並將其作爲參數發送給每個線程。如果我在任何線程中鎖定單詞,那麼將該單詞的實例鎖定在每個其他線程中,還是每個線程在啓動後都會創建單詞實例的副本? – sooprise 2012-02-22 16:13:22

+0

這是一個非常有用的帖子。我目前正在測試試圖保存它的腳本,如果失敗,它會鎖定對象,然後嘗試保存。只要這樣做,我仍然可以獲得使用多線程的速度優勢,並在保存失敗時獲得鎖定。 – sooprise 2012-02-22 17:16:27

+0

Aww,沒有工作:( – sooprise 2012-02-22 17:22:25