使用 ABAP 程式設計實現對微軟 Office Word 文件的操作

語言: CN / TW / HK

SAP ABAP 裡提供了一個標準的類 CL_DOCX_DOCUMENT,提供了本地以".docx"結尾的微軟 Office word 文件的讀和寫操作。

本文介紹了 ABAP 類 CL_DOCX_DOCUMENT 的簡單用法。

Office OpenXML

從微軟 Office2007 開始, 當我們新建一個 word 文件時,其副檔名從“.doc"變為了".docx",後者是基上遵循了一個開源的規範:Office openXML 格式。

例如下圖,我建立了一個最簡單的 word 文件,包含了一個 Header 區域,一個由三行彩色文字組成的段落,還有一張圖片。

我們把這個文件儲存到本地,將其副檔名從.docx 改成.zip, 然後雙擊,就可以用解壓軟體比如 winrar 開啟。

於是發現這一個最簡單的 word 文件實際上由如此多的 xml 和資料夾構成。

使用 CL_DOCX_DOCUMENT 讀取 word 檔案內容

示例程式碼如下:

DATA: lv_content TYPE xstring,
lo_document TYPE REF TO cl_docx_document.
PERFORM get_doc_binary USING 'C:Usersi042416Desktop est.docx' CHANGING lv_content.
lo_document = cl_docx_document=>load_document( lv_content ).
CHECK lo_document IS NOT INITIAL.
DATA(lo_core_part) = lo_document->get_corepropertiespart( ).
DATA(lv_core_data) = lo_core_part->get_data( ).
DATA(lo_main_part) = lo_document->get_maindocumentpart( ).
DATA(lo_image_parts) = lo_main_part->get_imageparts( ).
DATA(lv_image_count) = lo_image_parts->get_count( ).
DO lv_image_count TIMES.
DATA(lo_image_part) = lo_image_parts->get_part( sy-index - 1 ).
DATA(lv_image_data) = lo_image_part->get_data( ).
ENDDO.
DATA(lo_header_parts) = lo_main_part->get_headerparts( ).
DATA(lv_header_count) = lo_header_parts->get_count( ).
DO lv_header_count TIMES.
DATA(lo_header_part) = lo_header_parts->get_part( sy-index - 1 ).
DATA(lv_header_data) = lo_header_part->get_data( ).
ENDDO.

複製程式碼

上述程式碼的簡要說明

1. 將 word 文件的二進位制內容傳入方法 cl_docx_document=>load_document,得到一個文件物件引用,然後就可以藉助該物件引用呼叫各種方法了。

2. word 文件的建立者,建立時間,最後修改時間等資訊都儲存在所謂的“Core property part”內,可以通過方法 lo_document->get_corepropertiespart 獲得"Core property part"的引用,再使用該引用呼叫方法 get_data 獲得實際內容。

下圖是 get_data 返回的內容的一個例子,可以看出是 xml 格式。

3. 現在我們準備讀取 word 文件的正文了。使用方法 lo_document->get_maindocumentpart 得到 word 文件正文,文字的字型型別,顏色也包含在內。如下圖所示:

4. Word 文件裡插入的圖片的二進位制內容當然也是可以讀取出來的。使用方法:lo_image_parts->get_part 返回。

同樣的思路,微軟 Office 2007 之後版本的其他格式的辦公文件,比如 Powerpoint 和 Excel 等,均遵循 Office OpenXML 標準,因此將其後綴名改為.zip 後同樣可以看到大量 xml 和資料夾。ABAP 也同樣提供了標準程式碼來讀寫這些 Office 文件,例如 CL_PPTX_DOCUMENT, CL_XLSX_DOCUMENT 等等,如下圖所示。

相信對於"開發一個會產生死鎖的 Java 應用”這類需求,大家都能順利完成。但是如果題目要求得更具體一些,要求這個死鎖發生在資料庫層面,應該怎樣完成呢?

下面我提供一種答案,採用 SAP 的程式語言 ABAP(Advanced Business Application Programming)實現。

我們從 ABAP 幫助文件中得知,SELECT SINGLE FOR UPDATE 在從資料庫讀取一條記錄時,會在資料庫裡將該條記錄上鎖。幫助文件裡也提到,如果程式設計不恰當,會引起死鎖(deadlock)。

所以我們的答題就利用 SELECT SINGLE FOR UPDATE 這條語句。

首先在資料庫裡插入兩條記錄,主鍵分別為 Z01 和 Z02。

開發兩個應用,第一個應用依次鎖 Z01 和 Z02。

REPORT zlock1.
DATA: ls_prod TYPE zorder_header.
SELECT SINGLE FOR UPDATE * FROM zorder_header INTO ls_prod WHERE object_id = 'Z01'.
SELECT SINGLE FOR UPDATE * FROM zorder_header INTO ls_prod WHERE object_id = 'Z02'.
第二個應用依次鎖Z02和Z01。
REPORT zlock2.
DATA: ls_prod TYPE zorder_header.
SELECT SINGLE FOR UPDATE * FROM zorder_header INTO ls_prod WHERE object_id = 'Z02'.
SELECT SINGLE FOR UPDATE * FROM zorder_header INTO ls_prod WHERE object_id = 'Z01'.

複製程式碼

下面的步驟會造成資料庫層面的死鎖。

1. 以除錯模式執行第一個應用,單步執行完程式碼第 10 行,成功鎖住 Z01。

2. 新開一個視窗,以除錯模式執行第二個應用,單步執行完程式碼第 10 行,成功鎖住 Z02。

3. 回到應用 1 的視窗,繼續執行。此時應用 1 試圖鎖 Z02,但是 Z02 已經被應用 2 鎖住了,因此應用 1 處於等待狀態。

4. 回到應用 2 的視窗,繼續執行。此時應用 2 試圖鎖 Z01,但是 Z01 已經被應用 1 鎖住了,所以應用 2 只有等待應用 1 釋放出 Z01 的鎖。但應用 1 此時也在等待應用 2,因此造成了死鎖。

ABAP 和 Java 不同,一旦檢測到死鎖,應用會拋執行時異常並自動終止,異常資訊裡說得很清楚:Deadlock detected while executing transaction...

要獲取更多 Jerry 的原創技術文章,請關注公眾號"汪子熙".

劃線

評論

複製