自己動手做一個批次doc轉換為docx檔案的小工具

mingupupup發表於2024-03-20

前言

最近遇到了一個需求,就是要把大量的doc格式檔案轉換為docx檔案,因此就動手做了一個批次轉換的小工具。

背景

doc檔案是什麼?

"doc" 檔案是一種常見的檔案格式,通常用於儲存文字文件。它是 Microsoft Word 文件的副檔名。"doc" 是 "document" 的縮寫,表示這是一個文件檔案。這種檔案格式通常包含文字、影像、表格、圖形等內容,可以使用 Microsoft Word 或其他相容的文書處理軟體進行開啟和編輯。

docx檔案是什麼?

"docx" 檔案是 Microsoft Word 2007 及更高版本中使用的文件檔案格式的副檔名。它是 Office Open XML (OOXML) 標準的一部分,是一種基於 XML 的開放標準格式,用於儲存文字文件、影像、表格、圖形等內容。與早期的 ".doc" 格式相比,".docx" 格式具有更高的相容性和可擴充套件性,並且檔案大小通常更小。由於其開放的特性,許多其他文書處理軟體也支援 ".docx" 格式。

為什麼要將doc檔案轉化為docx檔案?

將 ".doc" 檔案轉換為 ".docx" 檔案的主要原因包括:

  1. 更先進的格式:".docx" 使用 Office Open XML 格式,這是一種更現代、更有效的檔案格式。它採用了基於 XML 的結構,使得檔案更容易解析和處理,同時也提供了更好的相容性和可擴充套件性。
  2. 減小檔案大小:由於 ".docx" 檔案採用了更高效的壓縮技術和檔案結構,相比 ".doc" 檔案通常會更小,這對於儲存和傳輸檔案是有利的。
  3. 相容性:許多最新版本的文書處理軟體更支援 ".docx" 格式,而較舊的 ".doc" 格式可能會在一些軟體中出現相容性問題。將檔案轉換為 ".docx" 格式可以確保在不同平臺和軟體中的良好相容性。
  4. 格式穩定性:".docx" 格式的結構更加穩定,不容易出現檔案損壞或格式錯誤的問題,從而提高了文件的可靠性。

綜上所述,將 ".doc" 檔案轉換為 ".docx" 檔案可以提高檔案的效率、相容性和穩定性,是一種值得推薦的做法。

實踐

方案使用C#透過Microsoft Office Interop實現將.doc檔案轉換為.docx檔案。

新增引用:

image-20240313204705350

前提是需要電腦上安裝有word。

頁面設計如下所示:

image-20240319211338214

選擇doc檔案所在的資料夾:

   // 建立一個新的FolderBrowserDialog
   FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

   // 設定FolderBrowserDialog的屬性
   folderBrowserDialog.Description = "請選擇待轉換的doc檔案所在的資料夾";

   // 顯示FolderBrowserDialog,並獲取結果
   if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
   {          
       docFolderPath = folderBrowserDialog.SelectedPath;
       richTextBox1.Text += $"你選擇的待轉換的doc檔案所在的資料夾是:{docFolderPath}\r\n";
   }

選擇儲存docx檔案的資料夾:

 // 建立一個新的FolderBrowserDialog
 FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

 // 設定FolderBrowserDialog的屬性
 folderBrowserDialog.Description = "請選擇儲存docx檔案的資料夾";

 // 顯示FolderBrowserDialog,並獲取結果
 if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
 {
     // 使用者已選擇一個資料夾,可以透過folderBrowserDialog.SelectedPath獲取所選資料夾的路徑
     docxFolderPath = folderBrowserDialog.SelectedPath;
     richTextBox1.Text += $"你選擇的儲存docx檔案的資料夾是:{docFolderPath}\r\n";
 }

開始轉換按鈕事件處理函式:

 if (docFolderPath == null || docxFolderPath == null)
 {
     MessageBox.Show("請先選擇doc檔案所在的資料夾與儲存docx檔案的資料夾");
 }
 else
 {

     await DocToDocx();
 }

為了避免阻塞介面,使用了非同步方法。

DocToDocx方法如下所示:

  public async System.Threading.Tasks.Task DocToDocx()
  {
      // 使用Task.Run來啟動一個新的非同步任務
      await System.Threading.Tasks.Task.Run(() =>
      {
          // 建立 Word 應用程式例項
          Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
       
          int i = 1;             
          // 遍歷所有.doc檔案
          foreach (string docFile in GetFiles(docFolderPath, "*.doc"))
          {
              // 開啟輸入的 .doc 檔案
              Document doc = wordApp.Documents.Open(docFile);

              // 獲取不帶副檔名的檔名
              string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(docFile);

              // 將副檔名改為.docx
              string docxFileName = Path.ChangeExtension(fileNameWithoutExtension, ".docx");

              string docxFilePath = Path.Combine(docxFolderPath, docxFileName);

              // 將 .doc 檔案儲存為 .docx 格式
              doc.SaveAs2(docxFilePath, WdSaveFormat.wdFormatXMLDocument);

              // 關閉 .doc 檔案
              doc.Close();

              // 釋放 Document 物件的資源
              System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);

              // 使用Invoke方法來更新richTextBox1
              richTextBox1.Invoke((Action)(() =>
              {
                  richTextBox1.Text += $"第{i}個檔案:{docFile}轉換完成 {DateTime.Now}\r\n";

                  // 設定插入點到文字的最後
                  richTextBox1.SelectionStart = richTextBox1.Text.Length;

                  // 滾動到插入點
                  richTextBox1.ScrollToCaret();
              }));

              i++;
          }

          // 退出 Word 應用程式
          wordApp.Quit();

          // 釋放資源
          System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp);
     
          // 使用Invoke方法來更新richTextBox1
          richTextBox1.Invoke((Action)(() =>
          {
              richTextBox1.Text += $"轉換完成 {DateTime.Now}\r\n";
          }));
      });         

GetFiles方法如下所示:

   // 這個方法返回一個IEnumerable<string>,表示檔案的路徑
  public IEnumerable<string> GetFiles(string path, string searchPattern)
  {
      // 獲取資料夾下的所有檔案
      string[] files = Directory.GetFiles(path, searchPattern);

      // 遍歷所有檔案
      foreach (string file in files)
      {
          // 返回當前檔案
          yield return file;
      }
  }

這裡使用了yield關鍵字,使用yield的好處如下:

  1. 延遲執行:迭代器的執行會被延遲,直到迭代器被消費時才開始。這意味著如果你有一個大的資料集合需要處理,但並不需要立即處理所有資料,那麼使用yield可以幫助你節省記憶體和計算資源。
  2. 簡化程式碼:yield可以使你的程式碼更簡潔,更易於閱讀和理解。你不需要建立一個臨時的集合來儲存你的結果,而是可以直接使用yield return來返回結果。
  3. 無需一次性生成所有結果:當處理大量資料時,一次性生成所有結果可能會消耗大量記憶體。使用yield可以在每次迭代時只生成一個結果,從而節省記憶體。

實現原理其實很簡單,就是用新版本的word開啟再儲存就行了。

 // 開啟輸入的 .doc 檔案
 Document doc = wordApp.Documents.Open(docFile);

 // 獲取不帶副檔名的檔名
 string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(docFile);

 // 將副檔名改為.docx
 string docxFileName = Path.ChangeExtension(fileNameWithoutExtension, ".docx");

 string docxFilePath = Path.Combine(docxFolderPath, docxFileName);

 // 將 .doc 檔案儲存為 .docx 格式
 doc.SaveAs2(docxFilePath, WdSaveFormat.wdFormatXMLDocument);

 // 關閉 .doc 檔案
 doc.Close();

 // 釋放 Document 物件的資源
 System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);

需要轉換的doc檔案所在的資料夾:

image-20240320160856832

軟體使用截圖:

image-20240320163426589

實現效果:

image-20240320163450275

實現了批次doc檔案轉換為docx檔案。

如果不熟悉C#也可以透過Python實現。

以下是一個檔案轉換的示例程式碼,經過測試可行:

import os
import win32com.client

def convert_doc_to_docx(doc_path):
    # 建立Word應用程式物件
    word = win32com.client.Dispatch("Word.Application")

    # 開啟.doc檔案
    doc = word.Documents.Open(doc_path)

    # 設定新的檔案路徑
    docx_path = os.path.splitext(doc_path)[0] + ".docx"

    # 儲存檔案為.docx格式
    doc.SaveAs(docx_path, FileFormat=16)  # 16 represents wdFormatXMLDocument

    # 關閉文件
    doc.Close()

    # 關閉Word應用程式
    word.Quit()

# 使用函式
convert_doc_to_docx("Path")

由於時間精力有限,沒有寫成批次處理的形式。

還有一種方案就是在word裡寫VBA。

採用哪種方案可以根據自己的熟練度。

相關文章