【问题标题】:Asynchronous creation and reading files [closed]异步创建和读取文件 [关闭]
【发布时间】:2020-11-28 21:03:40
【问题描述】:

以下代码创建一个临时 Word 文档,插入信体并返回临时 Word 文档的字节。

对于 50 个文档,以下代码需要 40 秒。

这里没有提供插入数据库的代码,但我确信它是临时文档创建,这需要最多时间,因为我做了一个 readallbytes 的 50 个 Word 文档并将它们插入数据库,不到 5秒。

    public async Task<byte[]> ConvertToWordDocument(string letterBody, int index)
    {
       string path = @"E:\Projects\temp" + index.ToString() + ".docx";

       byte[] bytesRead = null;

       await System.Threading.Tasks.Task.Run(() =>
       {
          var tempDoc = this.Application.Documents.Add(Visible: false);
  
          tempDoc.Content.Text = letterBody;
          tempDoc.SaveAs2(path, Word.WdSaveFormat.wdFormatDocumentDefault);
          tempDoc.Close();

          if (tempDoc != null)
             Marshal.ReleaseComObject(tempDoc);

       });

       bytesRead = File.ReadAllBytes(path);

       return bytesRead;
    }

代码应该做些什么,这样可以减少时间。

欢迎所有建议。

谢谢 苏杰

编辑:50 个文档的代码需要 40 秒。很抱歉之前没有提及 50 份文件。

【问题讨论】:

  • 第 1 步:分析您的应用程序,找出它花费最多/所有时间的地方。
  • 不要使用互操作。使用一些库,如 OpenXml、DocX、SpireDoc 等。
  • 我同意@LasseV.Karlsen 的观点,即您应该对其进行分析,但愿意打赌减速来自写入临时文件然后从其中读取。
  • 提示:使用这个 tmp 文件名生成器 :) string path = System.IO.Path.GetTempFileName();
  • @LasseV.Karlsen,创建临时 Word 文档所花费的时间最多。我可以在不到 5 秒的时间内将 50 个文档直接插入数据库。

标签: c# async-await word-addins


【解决方案1】:

据我了解,您使用 Microsoft.Office.Interop 在单独的进程中启动 Word 并通过 DCOM 推送数据\命令。 所以 40 秒对于该操作来说是相当长的时间。

为了加快速度,请尝试在没有 Word 应用程序的情况下撰写文档。看一下 open-xml-sdk: https://docs.microsoft.com/en-us/office/open-xml/open-xml-sdk

【讨论】:

    【解决方案2】:

    这是一个使用DocumentFormat.OpenXML 的选项。已使用 v2.11.3 测试

    在我的测试过程中,当使用 RichTextBox 获取文档文本时,在设置文本时似乎无法正确处理换行符。所以我找到了换行符序列。然后逐个字符地写入文本,遇到换行符时输入run.AppendChild(new Break());。这是我第一次使用 OpenXML——也许有更好的处理换行符的方法。它仍然相当快。在我的电脑上,这个用不到 1 秒的时间来创建 300 个文件(每个文件中的文本是 220 字)。

    将 Nuget 包“DocumentFormat.OpenXml”添加到项目中:(VS 2017 / VS 2019)

    • 查看
    • 解决方案资源管理器
    • 在解决方案资源管理器中,右键单击
    • 选择管理 Nuget 包...
    • 点击浏览
    • DocumentFormat.OpenXML
    • 点击安装

    添加对 WindowsBase 的引用:(VS 2017 / VS 2019)

    • 在菜单上,单击项目
    • 选择添加参考
    • 程序集
    • 框架
    • WindowsBase

    添加 using 语句:

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using System.Threading;
    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;
    using System.IO;
    using System.Diagnostics;
    

    创建一个类来保存创建 Word 文档所需的信息。

    WordFileInfo.cs

    public class WordFileInfo
    {
        public string Filename { get; set; }
        public string LetterBody { get; set; }
    
        public WordFileInfo()
        {
    
        }
    
        public WordFileInfo(string filename, string letterBody)
        {
            this.Filename = filename;
            this.LetterBody = letterBody;
        }
    }
    

    ClsHelperOpenXml.cs

    public class ClsHelperOpenXml
    {
        //depending on the number of files processed,
        //changing this value may increase/decrease performance slightly
        private int _maxConcurrentTasks = 25;
    
        //store data that needs to be processed
        public List<WordFileInfo> WordData { get; set; } = new List<WordFileInfo>();
    
        private enum NewLineSequence
        {
            None,
            Ascii10,
            Ascii13,
            Ascii1310,
        }
        public ClsHelperOpenXml()
        {
    
        }
    
        public ClsHelperOpenXml(List<WordFileInfo> wordData)
        {
            //set value
            this.WordData = wordData;
        }
    
        
        public void ConvertToWordDocument()
        {
            Debug.WriteLine("\nConverting to Word doc...");
    
            using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(_maxConcurrentTasks))
            {
                List<Task> tasks = new List<Task>();
                for (int i = 0; i < WordData.Count; i++)
                {
                    concurrencySemaphore.Wait();
    
                    var t1 = Task.Run(() =>
                    {
                        try
                        {
                            CreateWordDocument(WordData[i].Filename, WordData[i].LetterBody);
                        }
                        finally
                        {
                            concurrencySemaphore.Release();
                        }
    
                    }).ContinueWith(task =>
                    {
    
                        byte[] fBytes = File.ReadAllBytes(WordData[i].Filename);
                        return fBytes;
                    });
    
                    byte[] bytesRead = (byte[])t1.Result;
                    //System.Diagnostics.Debug.WriteLine("t1[" + i + "].Length: " + t1.Result.Length);
    
                    //add to list
                    tasks.Add(t1);
    
                }
    
                Task.WaitAll(tasks.ToArray());
    
                //clean up
                tasks.Clear();
            }
    
    
            Debug.WriteLine("Status: Complete " + DateTime.Now.ToString("HH:mm:ss"));
        }
        private void CreateWordDocument(string filename, string userText)
        {
            string errMsg = string.Empty;
            string result = string.Empty;
            
            if (String.IsNullOrEmpty(filename))
            {
                errMsg = "Error: CreateWordDocument - filename is null or empty.";
                Debug.WriteLine(errMsg);
                return;
            }
    
            if (String.IsNullOrEmpty(userText))
            {
                errMsg = "Error: CreateWordDocument - userText is null or empty.";
                Debug.WriteLine(errMsg);
                return;
            }
    
            //get newline sequence
            NewLineSequence nlSequence = GetNewLineSquence(userText);
    
            // Create a Wordprocessing document. 
            using (WordprocessingDocument doc = WordprocessingDocument.Create(filename, WordprocessingDocumentType.Document))
            {
    
                // Add a main document part.
                MainDocumentPart mainPart = doc.AddMainDocumentPart();
    
                // Create the document structure and add some text.
                mainPart.Document = new Document();
                Body body = mainPart.Document.AppendChild(new Body());
                Paragraph para = body.AppendChild(new Paragraph());
                Run run = para.AppendChild(new Run());
    
                string data = string.Empty;
                int previousVal = 0;
    
                if (!String.IsNullOrEmpty(userText))
                {
                    for (int i = 0; i < userText.Length; i++)
                    {
                        int charInt = Convert.ToInt32(userText[i]);
    
                        if (!(charInt == 10 || charInt == 13))
                        {
                            //append
                            data += userText[i];
                        }
                        else
                        {
                            //Debug.WriteLine(charInt + " " + nlSequence.ToString() + " previousVal: " + previousVal + " charInt: " + charInt );
    
                            //append text
                            run.AppendChild(new Text(data));
    
                            //re-initialize
                            data = string.Empty;
    
                            if ((nlSequence == NewLineSequence.Ascii1310 && previousVal == 13 && charInt == 10))
                            {
                                //add break;
                                run.AppendChild(new Break());
                            }
                            else if (nlSequence == NewLineSequence.Ascii10 && charInt == 10)
                            {
                                //add break
                                run.AppendChild(new Break());
                            }
                            else if (nlSequence == NewLineSequence.Ascii10 && charInt == 13)
                            {
                                //add break
                                run.AppendChild(new Break());
                            }
    
                        }
    
                        //set value
                        previousVal = charInt;
                    }
    
                    if (!String.IsNullOrEmpty(data))
                    {
                        //append text
                        run.AppendChild(new Text(data));
                        //run.AppendChild(new Break());
                    }
                }
    
                // Save changes to the main document part. 
                doc.MainDocumentPart.Document.Save();
            }
    
        }
    
        private NewLineSequence GetNewLineSquence(string userText)
        {
            int previousVal = 0;
    
            for (int i = 0; i < userText.Length; i++)
            {
                int charInt = Convert.ToInt32(userText[i]);
    
                if (charInt == 10 && previousVal == 13)
                {
                    return NewLineSequence.Ascii1310;
                }
                else if (charInt == 10 && previousVal != 13)
                {
                    return NewLineSequence.Ascii10;
                }
                else if (previousVal == 13 && charInt != 10)
                {
                    return NewLineSequence.Ascii13;
                }
    
                //set value
                previousVal = charInt;
            }
    
            return NewLineSequence.None;
        }
    }
    

    使用方法:

    我使用以下方法创建一些文件名和文档文本(用于测试)。

    创建测试数据

    private List<WordFileInfo> CreateTestData(string folderName, string sampleLetterBody)
    {
        //create data for testing
    
        int numTestFiles = 50; //for testing purposes
    
        List<WordFileInfo> wordData = new List<WordFileInfo>();
    
        for (int i = 0; i < numTestFiles; i++)
        {
            string filename = System.IO.Path.Combine(folderName, "WordDoc" + (i + 1).ToString() + ".docx");
    
            //add to list
            wordData.Add(new WordFileInfo(filename, sampleLetterBody));
    
            //Debug.WriteLine("Filename: '" + filename + "'");
        }
    
        return wordData;
    }
    

    然后使用以下命令来测试创建 Word 文档:

    string folderName = @"C:\Temp";
    string sampleLetterBody = "This is some text.";
    
    //get data for testing
    List<WordFileInfo> wordData = CreateTestData(folderName, sampleLetterBody);
    
    //create new instance (passing data using the constructor)
    ClsHelperOpenXml helperOpenXml = new ClsHelperOpenXml(wordData);
        
    helperOpenXml.ConvertToWordDocument();
    
    helperOpenXml = null;
        
    

    另见post

    【讨论】:

      【解决方案3】:

      更新:

      由于更新了原帖中的一些信息,我更新了这篇帖子。

      您可以尝试以下方法。在我的电脑上,选项 1 大约需要 8.5 秒。对于 50 个文件(每个文件中的文本为 220 个字),选项 2 大约需要 7.2 秒:

      添加对 Microsoft.Word 对象库的引用(例如:Microsoft.Word 16.0 对象库)

      • 在菜单上,点击项目
      • 选择添加参考
      • 选择COM
      • 选择 Microsoft.Word xx.x 对象库(例如:Microsoft.Word 16.0 对象库)

      添加以下 using 语句:

      using System.IO;
      using System.Diagnostics;
      using System.Runtime.InteropServices;
      using Word = Microsoft.Office.Interop.Word;
      using System.Threading;
      using System.Threading.Tasks;
      

      创建一个类来保存创建 Word 文档所需的信息。

      注意:以下有两个选项。两个选项都使用“WordFileInfo”类。

      WordFileInfo.cs:

      public class WordFileInfo
      {
          public string Filename { get; set; }
          public string LetterBody { get; set; }
      
          public WordFileInfo()
          {
      
          }
      
          public WordFileInfo(string filename, string letterBody)
          {
              this.Filename = filename;
              this.LetterBody = letterBody;
          }
      }
      

      在下面的两个选项中,“CreateWordDocument”在两者中完全相同。但是,我已将它包含在每个选项中,因为它是“ClsHelperWord.cs”的一部分。

      选项 1:

      *注意:此选项同时使用 Task 和 Backgroundworker。如果与 Windows 窗体一起使用,它有助于确保 UI 保持响应。由于使用了Backgroundworker,可能会稍微慢一些。

      创建用于从BackgroundWorker线程传回数据的“CurrentState”类。

      CurrentState.cs

      public class CurrentState
      {
          public string Status { get; set; } = string.Empty;
          public int PercentDone { get; set; } = 0;
      
      }
      

      ClsHelperWord.cs

      public class ClsHelperWord : IDisposable
      {
          //depending on the number of files processed,
          //changing this value may increase/decrease performance slightly
          private int _maxConcurrentTasks = 25; 
      
          //create new instance
          private Word.Application _wordApp = new Word.Application();
      
          //store data that needs to be processed
          public List<WordFileInfo> WordData { get; set; } = new List<WordFileInfo>();
      
      
          public ClsHelperWord()
          {
      
          }
      
          public ClsHelperWord(List<WordFileInfo> wordData)
          {
              //set value
              this.WordData = wordData;
          }
      
          public void Close()
          {
              Dispose();
          }
      
          public void Dispose()
          {
              if (_wordApp != null)
              {
                  //close Word
                  object oFalse = false;
                  _wordApp.Quit(ref oFalse, ref oFalse, ref oFalse);
      
                  //release all resources
                  System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_wordApp);
              }
          }
      
          public void ConvertToWordDocument(System.ComponentModel.BackgroundWorker worker, System.ComponentModel.DoWorkEventArgs e)
          {
              DateTime lastReportedDateTime = DateTime.MinValue;
              double percentDoneDbl = 0.0;
              int percentDoneInt = 0;
      
              //create new instance
              CurrentState state = new CurrentState(); 
              
              try
              {
                  Debug.WriteLine("\nConverting to Word doc...");
      
                  using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(_maxConcurrentTasks))
                  {
                      List<Task> tasks = new List<Task>();
                      for (int i = 0; i < WordData.Count; i++)
                      {
                          concurrencySemaphore.Wait();
      
                          state.Status = "Processing file " + i + " of " + WordData.Count + "...";
                          Debug.WriteLine(state.Status);
      
                          //-------------------------------
                          // report progress
                          //-------------------------------
                          if (i % 5 == 0)
                          {
                              if (worker.CancellationPending)
                              {
                                  e.Cancel = true;
                                  break;
                              } 
      
                              //ToDo: Do the following any time you want to
                              //update the status, progressBar, or any other
                              //variables you need updated during the
                              //background operation.
                              //Reporting progress too often will have a
                              //significant performance impact
      
                             
                              percentDoneDbl = (Convert.ToDouble(i) / Convert.ToDouble(WordData.Count)) * 100.0;
                              percentDoneInt = Convert.ToInt32(percentDoneDbl);
                              state.PercentDone = percentDoneInt;
      
                              worker.ReportProgress(0, state); //report progress back to form
                              lastReportedDateTime = DateTime.Now; //update last reported time
      
                          } 
      
                          //-------------------------------
                          // end of progress reporting
                          //-------------------------------
      
      
                          //create Word document(s)
                          var t1 = Task.Run(() =>
                          {
                              try
                              {
                                  CreateWordDocument(WordData[i].Filename, WordData[i].LetterBody);
                              }
                              finally
                              {
                                  concurrencySemaphore.Release();
                              }
      
                          }).ContinueWith(task =>
                          {
      
                              byte[] fBytes = File.ReadAllBytes(WordData[i].Filename);
                              return fBytes;
                          });
      
                          byte[] bytesRead = (byte[])t1.Result;
                          //System.Diagnostics.Debug.WriteLine("t1[" + i + "].Length: " + t1.Result.Length);
      
                          //add to list
                          tasks.Add(t1);
      
                      }
      
                      Task.WaitAll(tasks.ToArray());
      
                      //clean up
                      tasks.Clear();
                  }
      
      
                  Debug.WriteLine("Status: Complete " + DateTime.Now.ToString("HH:mm:ss"));
      
      
                  if (e.Cancel == true)
                  {
                      state.Status = "Status: Cancelled by user.";
                  }
                  else
                  {
                      state.PercentDone = 100;
                      state.Status = "Status: Complete.";
                  }
      
                  worker.ReportProgress(0, state); //report progress back to form
                  lastReportedDateTime = DateTime.Now; //update last reported time
      
              }
              finally
              {
                      //don't put any catch statements here so
                      //the errors will end up in e.Error in
                      //backgroundWorker1_RunWorkerCompleted.
                      //Handle the errors in
                      //backgroundWorker1_RunWorkerCompleted.
                  
              }
          }
      
      private string CreateWordDocument(string filename, string userData)
      {
          //*Note: All indices start at 1. 
      
          string result = string.Empty;
      
          //set value
          object oMissing = System.Reflection.Missing.Value;
          object oEndOfDoc = "\\endofdoc"; /* \endofdoc is a predefined bookmark */
      
          Word.Documents documents = null;
          Word.Document doc = null;
      
          bool isVisible = false;
      
      
          try
          {
      
              //suppress displaying alerts (such as prompting to overwrite existing file)
              _wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
      
              //set Word visibility
              _wordApp.Visible = isVisible;
      
              //if writing/updating a large amount of data
              //disable screen updating by setting value to false
              //for better performance.
              //re-enable when done writing/updating data, if desired
              //_wordApp.ScreenUpdating = false;
      
              if (_wordApp != null)
              {
                  if (File.Exists(filename))
                  {
                      //System.Diagnostics.Debug.WriteLine("'" + filename + "' exists. Existing file will be modified.");
      
                      //open existing Word document
                      documents = _wordApp.Documents;
                      doc = documents.Open(filename, System.Reflection.Missing.Value, false, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, isVisible, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
                      doc.Activate();
                  }
                  else
                  {
                      //create new document
                      doc = _wordApp.Documents.Add();
                      doc.Activate();
      
                      //Debug.WriteLine("Created new document");
                  }
      
                  if (doc == null)
                  {
                      Debug.WriteLine("Error: doc is null");
                      return null;
                  }
      
                  //set text
                  doc.Content.Text = userData;
      
                  if (!_wordApp.ScreenUpdating)
                  {
                      //in case screen updating was previously disabled, 
                      //enable screen updating by setting value to true
                      _wordApp.ScreenUpdating = true;
      
                      //refresh screen
                      //_wordApp.ScreenRefresh();
                  }
      
                  if (!String.IsNullOrEmpty(filename))
                  {
                      try
                      {
                          //Debug.WriteLine("Saving to '" + filename + "'");
      
                          //save the document
                          //doc.SaveAs(filename, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
      
                          doc.SaveAs2(filename, Word.WdSaveFormat.wdFormatXMLDocument, CompatibilityMode: Word.WdCompatibilityMode.wdWord2013);
      
                      }//try
                      catch (Exception ex)
                      {
                          string errMsg = "Error: WordWriteDocument - " + ex.Message;
                          System.Diagnostics.Debug.WriteLine(errMsg);
      
                          if (ex.Message.StartsWith("Cannot access read-only document"))
                          {
                              System.Windows.Forms.MessageBox.Show(ex.Message + "Please close the Word document, before trying again.", "Error - Saving", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                          }
                      }
                  }
      
                  //set value
                  result = "Success";
              }
      
          }
          catch (Exception ex)
          {
              string errMsg = "Error: WordWriteDocument - " + ex.Message;
              System.Diagnostics.Debug.WriteLine(errMsg);
          }
          finally
          {
              
              if (doc != null)
              {
                  //close document
                  doc.Close(Word.WdSaveOptions.wdDoNotSaveChanges, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
      
                  //release all resources
                  System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
              }
      
          }
      
          return result;
      }
      

      使用方法:

      添加以下声明(到 Windows 窗体、UserControl 或 Class)。或者,如果使用 Windows 窗体,则可以从 ToolBox 添加 Backgroundworker。

      private BackgroundWorker backgroundWorker1 = new BackgroundWorker();
      private ClsHelperWord helperWord = null;
      

      设置 Backgroundworker 属性并订阅事件——这可以放在构造函数中。

      //set properties
      backgroundWorker1.WorkerReportsProgress = true;
      backgroundWorker1.WorkerSupportsCancellation = true;
      
      //subscribe to events (add listener)
      backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
      backgroundWorker1.ProgressChanged += BackgroundWorker1_ProgressChanged;
      backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;
      

      BackgroundWorker1_DoWork

      private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
      {
          System.ComponentModel.BackgroundWorker worker;
          worker = (System.ComponentModel.BackgroundWorker)sender;
          ClsHelperWord myClsHelperWord = (ClsHelperWord)e.Argument;
      
          helperWord.ConvertToWordDocument(worker, e);
      } 
      

      BackgroundWorker1_ProgressChanged

      private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
      {
          CurrentState state = (CurrentState)e.UserState;
      
          Debug.WriteLine(state.Status + " " + state.PercentDone.ToString());
      }
      

      BackgroundWorker1_RunWorkerCompleted

      private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
      {
      
          if (e.Error != null)
          {
              // Handle the errors here.
              // Write error message to console
              // and/or a log file.
      
              Debug.WriteLine("Error: " + e.Error.Message);
      
              if (helperWord != null)
              {
                  helperWord.Dispose();
                  helperWord = null;
              }
      
          } 
          else if (e.Cancelled)
          {
              Debug.WriteLine("Cancelled by user.");
      
              if (helperWord != null)
              {
                  helperWord.Dispose();
                  helperWord = null;
              }
      
          } 
          else
          {
              string finalStatus = "Status: Complete.";
              Debug.WriteLine(finalStatus);
      
              //clean up
              if (helperWord != null)
              {
                  helperWord.Dispose();
                  helperWord = null;
              }
          } 
      } 
      

      我使用以下方法创建一些文件名和文档文本(用于测试)。

      创建测试数据

      private List<WordFileInfo> CreateTestData(string folderName, string sampleLetterBody)
      {
          //create data for testing
      
         int numTestFiles = 50; //for testing purposes
      
         List<WordFileInfo> wordData = new List<WordFileInfo>();
      
          for (int i = 0; i < numTestFiles; i++)
          {
              string filename = System.IO.Path.Combine(folderName, "WordDoc" + (i + 1).ToString() + ".docx");
      
              //add to list
              wordData.Add(new WordFileInfo(filename, sampleLetterBody));
      
              //Debug.WriteLine("Filename: '" + filename + "'");
          }
      
          return wordData;
      }
      

      然后使用以下命令来测试创建 Word 文档:

      string folderName = @"C:\Temp";
      string sampleLetterBody = "This is some text.";
      
      //get data for testing
      List<WordFileInfo> wordData = CreateTestData(folderName, sampleLetterBody);
      
      if (helperWord != null)
      {
          helperWord.Dispose();
          helperWord = null;
      }
      
      //create new instance and set property
      helperWord = new ClsHelperWord(wordData);
      
      if (backgroundWorker1.IsBusy != true)
      {
          backgroundWorker1.RunWorkerAsync(helperWord);
      }//if
      

      选项 2:

      *注意:如果与 Windows 窗体一起使用,此选项可能会导致 UI 无响应。

      ClsHelperWord.cs

      public class ClsHelperWord : IDisposable
      {
          //depending on the number of files processed,
          //changing this value may increase/decrease performance slightly
          private int _maxConcurrentTasks = 25; 
      
          //create new instance
          private Word.Application _wordApp = new Word.Application();
      
          //store data that needs to be processed
          public List<WordFileInfo> WordData { get; set; } = new List<WordFileInfo>();
      
      
          public ClsHelperWord()
          {
      
          }
      
          public ClsHelperWord(List<WordFileInfo> wordData)
          {
              //set value
              this.WordData = wordData;
          }
      
          public void Close()
          {
              Dispose();
          }
      
          public void Dispose()
          {
              if (_wordApp != null)
              {
                  //close Word
                  object oFalse = false;
                  _wordApp.Quit(ref oFalse, ref oFalse, ref oFalse);
      
                  //release all resources
                  System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_wordApp);
              }
          }
      
          public void ConvertToWordDocument()
          {
              Debug.WriteLine("\nConverting to Word doc...");
      
              using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim (_maxConcurrentTasks))
              {
                  List<Task> tasks = new List<Task>();
                  for (int i = 0; i < WordData.Count; i++)
                  {
                      concurrencySemaphore.Wait();
      
                      var t1 = Task.Run(() =>
                      {
                          try
                          {
                              CreateWordDocument(WordData[i].Filename, WordData[i].LetterBody);
                          }
                          finally
                          {
                              concurrencySemaphore.Release();
                          }
                          
                      }).ContinueWith(task =>
                      {
      
                          byte[] fBytes = File.ReadAllBytes(WordData[i].Filename);
                          return fBytes;    
                      });
      
                      byte[] bytesRead = (byte[])t1.Result;
                      //System.Diagnostics.Debug.WriteLine("t1[" + i + "].Length: " + t1.Result.Length);
      
                      //add to list
                      tasks.Add(t1);
      
                  }
      
                  Task.WaitAll(tasks.ToArray());
      
                  //clean up
                  tasks.Clear();
              }
      
      
              Debug.WriteLine("Status: Complete " + DateTime.Now.ToString("HH:mm:ss"));
          }
      
       
      private string CreateWordDocument(string filename, string userData)
          {
              //*Note: All indices start at 1. 
      
              string result = string.Empty;
      
              //set value
              object oMissing = System.Reflection.Missing.Value;
              object oEndOfDoc = "\\endofdoc"; /* \endofdoc is a predefined bookmark */
      
              Word.Documents documents = null;
              Word.Document doc = null;
      
              bool isVisible = false;
      
      
              try
              {
      
                  //suppress displaying alerts (such as prompting to overwrite existing file)
                  _wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
      
                  //set Word visibility
                  _wordApp.Visible = isVisible;
      
                  //if writing/updating a large amount of data
                  //disable screen updating by setting value to false
                  //for better performance.
                  //re-enable when done writing/updating data, if desired
                  //_wordApp.ScreenUpdating = false;
      
                  if (_wordApp != null)
                  {
                      if (File.Exists(filename))
                      {
                          //System.Diagnostics.Debug.WriteLine("'" + filename + "' exists. Existing file will be modified.");
      
                          //open existing Word document
                          documents = _wordApp.Documents;
                          doc = documents.Open(filename, System.Reflection.Missing.Value, false, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, isVisible, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
                          doc.Activate();
                      }
                      else
                      {
                          //create new document
                          doc = _wordApp.Documents.Add();
                          doc.Activate();
      
                          //Debug.WriteLine("Created new document");
                      }
      
                      if (doc == null)
                      {
                          Debug.WriteLine("Error: doc is null");
                          return null;
                      }
      
                      //set text
                      doc.Content.Text = userData;
      
                      if (!_wordApp.ScreenUpdating)
                      {
                          //in case screen updating was previously disabled, 
                          //enable screen updating by setting value to true
                          _wordApp.ScreenUpdating = true;
      
                          //refresh screen
                          //_wordApp.ScreenRefresh();
                      }
      
                      if (!String.IsNullOrEmpty(filename))
                      {
                          try
                          {
                              //Debug.WriteLine("Saving to '" + filename + "'");
      
                              //save the document
                              //doc.SaveAs(filename, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
      
                              doc.SaveAs2(filename, Word.WdSaveFormat.wdFormatXMLDocument, CompatibilityMode: Word.WdCompatibilityMode.wdWord2013);
      
                          }//try
                          catch (Exception ex)
                          {
                              string errMsg = "Error: WordWriteDocument - " + ex.Message;
                              System.Diagnostics.Debug.WriteLine(errMsg);
      
                              if (ex.Message.StartsWith("Cannot access read-only document"))
                              {
                                  System.Windows.Forms.MessageBox.Show(ex.Message + "Please close the Word document, before trying again.", "Error - Saving", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                              }
                          }
                      }
      
                      //set value
                      result = "Success";
                  }
      
              }
              catch (Exception ex)
              {
                  string errMsg = "Error: WordWriteDocument - " + ex.Message;
                  System.Diagnostics.Debug.WriteLine(errMsg);
              }
              finally
              {
                  
                  if (doc != null)
                  {
                      //close document
                      doc.Close(Word.WdSaveOptions.wdDoNotSaveChanges, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
      
                      //release all resources
                      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
                  }
      
              }
      
              return result;
          }
      }
      

      使用方法:

      我使用以下方法创建一些文件名和文档文本(用于测试)。

      创建测试数据

      private List<WordFileInfo> CreateTestData(string folderName, string sampleLetterBody)
      {
          //create data for testing
      
         int numTestFiles = 50; //for testing purposes
      
         List<WordFileInfo> wordData = new List<WordFileInfo>();
      
          for (int i = 0; i < numTestFiles; i++)
          {
              string filename = System.IO.Path.Combine(folderName, "WordDoc" + (i + 1).ToString() + ".docx");
      
              //add to list
              wordData.Add(new WordFileInfo(filename, sampleLetterBody));
      
              //Debug.WriteLine("Filename: '" + filename + "'");
          }
      
          return wordData;
      }
      

      然后使用以下命令来测试创建 Word 文档:

      string folderName = @"C:\Temp";
      string sampleLetterBody = "This is some text.";
      
      //get data for testing
      List<WordFileInfo> wordData = CreateTestData(folderName, sampleLetterBody);
      
      using (ClsHelperWord helperWord = new ClsHelperWord(wordData))
      {
          helperWord.ConvertToWordDocument();
      }
      

      以下帖子也可能会有所帮助。

      【讨论】:

      • 抱歉提供错误信息。 50 个文档需要 40 秒。已更新问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      相关资源
      最近更新 更多