<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Gopher China 分享:Go 語言電子表格辦公文檔格式標準實踐

          共 9226字,需瀏覽 19分鐘

           ·

          2021-07-25 13:45

          9T0J2pD1GY.jpg


          Gopher China 致力于為中國廣大的 Go 語言開發(fā)者提供最好的交流平臺,國內(nèi)最權(quán)威和最干貨的 Go 語言大會,匯集廣大 Go 語言的開發(fā)者以及大規(guī)模應用 Go 的示范企業(yè)給大家?guī)砭史窒怼?/p>


          bdsgtohdQg.jpg


          第七屆 Gopher China 大會于 2021 年 6 月 26 日至 27 日在北京舉辦。本次會上,續(xù)日帶來了題為《Go 語言電子表格辦公文檔格式標準實踐》的主題分享,以下是分享實錄。


          4bpMtypn4M.jpeg

          這是我的自我介紹,今天為什么要分享這個主題呢,我說一下準備這次分享背后的思考:近年來,隨著在線辦公的興起,對辦公文檔云端處理有了更多需求; 企業(yè)信息化、數(shù)字化建設過程中,各類報表系統(tǒng)、企業(yè)應用對數(shù)據(jù)收集、錄入和加工的場景越來越多,在這些場景中經(jīng)常需要通過編程方式處理辦公文檔提供支持。XML 是一種應用十分廣泛的數(shù)據(jù)標記語言,Excel 辦公文檔是應用復雜 XML 的典型代表之一,那么我的 Topic 就結(jié)合實踐給大家分享使用 Go 語言在處理 XML 和 Excel 電子表格文檔過程中的經(jīng)驗。


          YTv71FyHNi.jpeg


          本次 Topic 有四個部分:第一部分:處理 XML 的基本模式和 Go 語言解析 XML 的原理;第二部分:Go 處理復雜 XML 時的一些技巧、遇到過的問題以及解決方式;第三部分:基于模式的 XML 解析,如何高效處理大規(guī)模 XML 文檔;第四部分將介紹 Go 語言如何實現(xiàn) Excel 電子表格文檔標準、以及如何高效做流式處理。今天的 PPT 中會包含很多具體的代碼實例。


          HfQa6lwGjJ.jpeg


          首先是序列化與反序列化技術(shù)。先說反序列化技術(shù),也就是對 XML 文檔的解析,其典型處理方式分為兩種:基于對象模型的處理和基于事件驅(qū)動的處理。

          oolm6GE2vI.jpeg

          基于對象模型的處理方式,需要先對文檔對象模型(DOM)進行定義,在 Go 語言中就是定義結(jié)構(gòu)體。例如對于這個 XML 文檔進行解析,與之對應的數(shù)據(jù)結(jié)構(gòu):Go 語言結(jié)構(gòu)體 Person,結(jié)構(gòu)體中有 Name、Email 等字段,與 XML 中的標簽、屬性一一對應,然后聲明并初始化變量 p 為 Person 類型,調(diào)用 Go 語言標準庫 encoding/xml 提供的 Unmarshal 函數(shù),對 XML 文檔進行解析,接著將解析結(jié)果輸出。可以看到 XML 文檔已經(jīng)被正確地解析,標簽和屬性被映射到 Person 結(jié)構(gòu)體中對應的字段中。至此一個簡單的解析 XML 就完成了。

          p7MjwWtSAw.jpeg

          那么這樣一個看似簡單的過程,背后是如何實現(xiàn)的呢,先了解一下對 XML 文本進行詞法分析,根據(jù)輸入字符構(gòu)成的詞素狀態(tài)建立 NFA 非確定型有限狀態(tài)自動機,當輸入一個字符或者條件得到一個狀態(tài)機的集合,實現(xiàn)對 XML 的解析過程要比 JSON 相對復雜,這里我們主要關(guān)注 6 個狀態(tài):start tag、end tag、COMMENT、Version、Name 和 Text。


          HAzpAwEY04.jpeg


          Go 語言標準庫中對 XML 的處理共 4 個源碼文件,當我們調(diào)用 Unmarshal 進行反序列化操作的時候,主要的內(nèi)部處理過程是這樣的,先通過 NewDecoder 初始化 Decoder 對象,程序判斷當前為反序列化操作,switcherToReader 進入 XML 解析模式,對 XML 狀態(tài)機的實現(xiàn)在 RawToken 內(nèi)部函數(shù)中進行,在詞法分析每個子狀態(tài)中調(diào)用對應的處理指令(例如 pushElement、pushNs 等)構(gòu)建 Token,接著調(diào)用 unmarshal 函數(shù),通過反射對象模型內(nèi)的字段信息,將不同類型的 Token 通過 unmarshalAttr、unmarshalInterface、unmarshalPath 等函數(shù)到對應的 Field 上面,完成解析過程。


          IZwLO0tP32.jpeg


          觀察 Decoder 解碼器的數(shù)據(jù)結(jié)構(gòu)定義,其中字段 Strict 定義了 XML 解析模式,AutoClose 用來處理自關(guān)閉標簽,Entity 處理 XML 實體還包含其他 15 個未導出字段供內(nèi)部處理使用。Go 語言中 XML _Token 主要分為六大類:StartElement 起始標簽、EndElement 結(jié)束標簽、CharData 字符數(shù)據(jù)、Comment 注釋、ProcInst 和 Directive 是 XML 處理指令。在使用 Unmarshal 解析 XML 文檔的時候,標準庫內(nèi)部先是通過 Decoder 讀取 XML 文本字符流,這是一種流式解析方式,再此過程生成 Token 確定當前解析狀態(tài),所以通過 Token 的類型可以得知當前解析進程,基于 Token 對 XML 文檔進行的解析就是事件驅(qū)動解析模式。


          jxDBaUf2Ve.jpeg

          基于事件的驅(qū)動方式,可以直接調(diào)用 Go 語言 XML 標準庫提供的 NewDecoder 方法,遍歷 Token 終止條件為當其值為 nil,根據(jù) Token 類型可以獲得當前解析事件,常用的是 StartElemtent 和 EndElement 兩個事件,該方式給開發(fā)者暴露了相對底層的接口,使用基于事件的方式處理同樣一個 XML 文檔,輸出結(jié)果與 XML 文檔中標簽開閉的順序相一致,顯然這種方式無法進行回溯,如有需要開發(fā)者必須在程序內(nèi)部自行維護與狀態(tài)。對于一般普通的簡單 XML 文檔解析,使用基于文檔模型的方式更靈活方便,Go 語言提供了多種解析與生成控制 flags。

          WTKyckhWIN.jpeg

          關(guān)于反序列化和序列化控制,在標準庫的 typeinfo.go 源碼中定義了可用于在文檔對象模型數(shù)據(jù)結(jié)構(gòu)中使用的 Tag,主要有 7 種:帶有 ”,attr” 標簽的字段會成為 XML 元素的屬性,其中屬性的名字為字段的名字;帶有 ”,cdata” 和 ”,chardata” 標簽的字段將會被封裝為字符數(shù)據(jù)而不是 XML 元素;帶有 ”,innerxml” 標簽的字段會以原樣進行解析和編碼;帶有 ”,comment” 標簽會被作為注釋解析和編碼;帶有 ”,any” 標簽的字作為以上幾種規(guī)則失效的 failback 映射;帶有 “omitempty” 選項的字段,其值為空時,這個字段將被忽略不參與解析與編碼。在這個例子中,Tag 聲明了結(jié)構(gòu)體中的 Where 字段對應 XML 文檔中的 where 屬性,并且當該值為空的時候,不會進行反序列化和序列化。


          CjcSASb6wu.jpeg


          利用控制 Tag 可以在業(yè)務中實現(xiàn)局部解析,在這個這個例子中,Person 包含 Name 和 Email 兩個子標簽,而 Email 還包含一個 Addr 的子標簽,如果希望 Email 被延遲解析,可以將 Email 單獨定義為 innerXML,當后續(xù)有解析需要時再對 Email.Content 進行一次反序列化操作即可,可以看到 Email 的 Content 沒有參與解析,其原始值被保留。這種方式在處理嵌套層級深且復雜的 XML 文檔時是一個可以參考的方法,避免了不必要的資源消耗有助于提高性能。

          y5fXDvNW3n.jpeg


          接下來進一步聊一聊對于復雜 XML 的處理,XML 標準是一套復雜的規(guī)范,Go 語言并沒有完全對該標準進行實現(xiàn),在實際生產(chǎn)應用過程中一些復雜情形需要做一些額外的處理,下面介紹 Go 在處理 XML 文檔時在數(shù)據(jù)類型、實體和冪等性三個方面遇到的問題或需要注意的點。


          UwLfM9TTHa.jpeg

          首先是數(shù)據(jù)類型,XML 標準規(guī)范中定的數(shù)據(jù)類型有 49 個,其中包含用戶派生數(shù)據(jù)類型(紫色)、內(nèi)置原始數(shù)據(jù)類型(淡紫色)、內(nèi)置派生數(shù)據(jù)類型(藍色)和復合數(shù)據(jù)類型(白色),它們的派生關(guān)系如右側(cè)這張圖片所示。左側(cè)這張表梳理了 Go 語言的數(shù)據(jù)類型與 XML 數(shù)據(jù)類型之間的映射關(guān)系。當我們在處理復雜 XML 文檔或在跨語言處理 XML 文檔時需要關(guān)注數(shù)據(jù)類型的問題,數(shù)據(jù)類型的不一致可能導致潛在的數(shù)據(jù)校驗失敗、數(shù)據(jù)精度錯誤等問題,對于 XML 專有的數(shù)據(jù)類型根據(jù)需要單獨實現(xiàn)。


          WhggsVFuf9.jpeg


          XML 實體是用于定義引用普通文本或特殊字符的快捷方式的變量,在這個例子中包含兩個實體聲明 name 和 email,而 person 中的 &name; 和 &email; 是實體引用,Go 語言目前不完全支持對該 XML 的解析,需要開發(fā)者先對實體進行提取,在已經(jīng)了解 Go 語言內(nèi)部是如何處理 XML 文檔的原理之后,可以知道實體信息存儲于Directive 類型的 Token 中,通過正則表達式對實體聲明進行模式匹配進行提取,將提取結(jié)果輸出驗證。


          EgTkhQqe2G.jpeg

          在提取實體聲明之后再進行 XML 解析,關(guān)閉 XML 嚴格模式并設置 Decoder 的 Entity 為剛剛提取到的實體聲明即可。將解析結(jié)果輸出驗證可以看到帶有實體的 XML 文檔被正確解析。


          aURz990BGW.jpeg


          這是一個處理帶有多命名空間 XML 的例子:標簽 person 中聲明了默認命名空間和其余三個命名空間 m、h 和 w,標簽 m 擁有兩個隸屬于不同命名空間下的同名屬性 addr,在解析該 XML 文檔時需要將命名空間 URI 在控制 Tag 中的屬性名稱當中聲明,需要注意的是標簽 email 在 m 命名空間下,它的命名空間需要在 Email 結(jié)構(gòu)體中通過 xml.Name 聲明,而不是定義在結(jié)構(gòu)體外,這樣就可以正確解析帶有多命名空間的 XML 文檔到 Person 結(jié)構(gòu)體中了,然而如果將反序列化后到對象通過 Marshal 序列化,person 中除默認命名空間之外的其余命名空間全部丟失,這就是反序列化 / 序列化冪等性問題,序列化輸出與原始 XML 文檔內(nèi)容存在內(nèi)容缺失。


          3CQ1Z05yKi.jpeg


          為了解決該問題,需要先了解 Go 語言中對 XML 命名空間和文檔對象模型是如何映射的:每個 StartElement 類型的 Token 中都有一個名為 Name 的字段用以映射命名空間,還有一個 Attr 數(shù)組用以存儲該標簽的屬性。Name 數(shù)據(jù)結(jié)構(gòu)中定義了命名空間名稱和 Local name,Attr 結(jié)構(gòu)體中也有名為 Name 字段用以存儲該標簽的命名空間,所以在解析 XML 后命名空間的原始結(jié)構(gòu)沒有丟失,開發(fā)者可以通過事件驅(qū)動解析的方式實現(xiàn)一個 getRootEleAttr 的函數(shù)來收集并存儲 XML 文檔根標簽的全部屬性。


          qvkh0q4OGv.jpeg


          當序列化帶有多命名空間的 XML 時,如果根節(jié)點標簽命名空間無變化,可以在基于事件解析的過程中通過根標簽屬性中的 Name.Space、Name.Local 和 attr.Value 構(gòu)造命名空間聲明字符,替換序列化結(jié)果中的 root element;如果在解析 XML 后根標簽屬性中的命名空間信息有改變,維護解析時通過 getRootEleAttr 得到的命名空間信息,序列化時同樣可以拼接出帶有完整 namespace 的 root element,這樣即可保證反序列化 / 序列化冪等。


          3kTvWU9FFe.jpeg


          在 Topic 的第三部分,分享高效處理 XML 的經(jīng)驗。這里的高效從兩方面理解:一方面是在處理大規(guī)模復雜 XML 文檔時如何保證功能實現(xiàn)的高效;另一方面是如何在 DOM 解析和 SAX 解析方式上做選擇實現(xiàn)高性能。


          q4rTkzcAcw.jpeg


          先來看如何保證功能實現(xiàn)的高效。來看這樣一個例子:一個根標簽為 note 的 XML 文檔,其 XSD 模式描述如下,XSD 是對 XML 的模式描述,對于大規(guī)模 XML 文檔可根據(jù) XSD 對 XML 做驗證?;氐竭@個例子中,XSD 中通過 element 聲明了名為 note 的對象是一個標簽,complexType 聲明該標簽包含一個復雜類型對象,sequence 聲明該復雜類型對象包含子標簽序列,按順序依次有 4 個子標簽,其中 body 標簽在名為 m 的命名空間下、且為必選標簽,在 XSD 第 2 行聲明了該命名空間的 URI,第 3 行聲明該命名空間引自外部名為 shared.xsd 的模式中;在 shared.xsd 中定義了標簽 body 的數(shù)據(jù)類型為 string。


          zP7pKGfzeH.jpeg

          基于 XSD 模式可以定義解析該 XML 的文檔對象模型 Go 語言結(jié)構(gòu)體最終如下。我們需要解析的 XML 文件中包含很多可選標簽或?qū)傩?,尤其在大?guī)模 XML 處理過程中,可以利用 XSD 模式高效生成文檔對象模型。


          1e2BCx3o5m.jpeg


          這是 XML 模式組件數(shù)據(jù)模型的 UML 類圖,我們可以直觀理解 XML 模式的基本組成,進而通過 XSD 可以生成解析 XML 文檔的文檔對象模型,這種方式在處理大規(guī)模復雜 XML 模式時能夠有效提升開發(fā)速度。其翻譯過程如右圖所示:基于事件驅(qū)動解析 XML 文檔,并根據(jù)模式狀態(tài)機將 Token 映射到模式 proto 上完成內(nèi)存模型的準備工作,文檔模型的生成針對每個 XSD 組件分別實現(xiàn)代碼生成器,最終可以為 Go、TypeScript、C、Java 和 Rust 等語言生成 XML 文檔對象模型代碼。這種方法應用于 Excel 電子表格文檔基礎庫的實現(xiàn)過程中,效果十分顯著,Office 辦公文檔中包含超過數(shù)以萬計 XML 標簽和屬性,這些標簽組合嵌套錯綜復雜,如果人工定義編寫結(jié)構(gòu)體工程量十分龐大且容易出錯,文檔對象模型代碼的生成可將 XSD 轉(zhuǎn)化為 Go 語言結(jié)構(gòu)體代碼,大幅提升開發(fā)效率。


          TulzPLdvNd.jpeg


          再談 XML 處理的性能:對于基于事件的 SAX 解析和基于文檔對象模型的 DOM 解析如何抉擇?表格中總結(jié)了兩種方式的優(yōu)缺點??偟膩碚f DOM 方式更適合處理復雜 XML 文檔、內(nèi)存占用相對較高、開發(fā)維護成本低;SAX 方式適合處理結(jié)構(gòu)簡單的 XML 大文件,更省內(nèi)存占用,但無法回溯,維護成本相對較高。實際業(yè)務中兩種解析方式根據(jù)場景來做選擇。


          NWiexSMDv9.jpeg


          進入分享的第四部分:下面將分享 Go 語言在處理 Excel 電子表格辦公文檔方面的實踐。


          AF1kHz9QVx.jpeg


          Office 辦公文檔的技術(shù)標準:兩個名稱 ISO/IEC 29500 或 ECMA-376,簡稱 OOXML,是基于 XML 技術(shù)的國際標準。大家所熟知的 Word、Excel、PowerPoint 辦公文檔都遵循該標準。這是一套十分龐大復雜的技術(shù)標準,這張圖來自中國工程院倪光南院士在中歐研討會上的分享,對比了 OOXML 與其他國際技術(shù)標準,橫軸是標準規(guī)格書的頁數(shù),也就是描述該標準文檔的頁數(shù);縱軸是技術(shù)委員會討論天數(shù),可以看到像 ODF、SVG 等技術(shù)標準的規(guī)格書都在 1000 頁以內(nèi),形成標準周期在三年左右,而 OOXML 的標準規(guī)格書長達 6000 余頁,大家可以在 ECMA 或 ISO 國際標準化網(wǎng)站下載該文檔。Excelize 是 Go 語言操作電子表格文檔的基礎庫,對該標準的部分內(nèi)容進行了實現(xiàn),下面我先向大家簡要介紹該標準內(nèi)容。


          2sypwbLYWq.jpeg


          OOXML 的底層是基于 ZIP、XML 和 Unicode 的核心技術(shù),將一個 Office 文檔擴展名修改為 zip 進行解壓即可得到一個文件夾,其中包含若干子文件夾和 XML 文檔,這種設計相比于二進制類型文檔格式也具備更好的兼容性。向上一層為開放包裝公約(Open Packaging Convention),簡稱 OPC,定義了文檔內(nèi)部組件之間的關(guān)聯(lián)依賴關(guān)系(Relationships)、文檔內(nèi)容類型(Content Types)和數(shù)字簽名(Digital Signatures)。通用標記是跨應用的文本標記語言:囊括可視化圖表、可擴展標記、源數(shù)據(jù)和目錄引用等。上層是標記語言部分(Markup Language),它由四類標記語言組成:Word 文檔對應的標記語言叫 WordprocessingML,電子表格則是 SpreadsheetML,演示文稿對應的是 PresentationML。除此之外 Office 文檔支持進行跨應用的嵌套,例如:Word、PowerPoint 中可以嵌套 Excel。


          DTeeWwGhUi.jpeg


          使用 Go 語言實現(xiàn)電子表格文檔基礎庫,需要實現(xiàn)的圖中橙色高亮的部分,通過 XSD 的定義可以得知其中涉及 XML 標簽和屬性的分布情況:Drawing 有 9918 個,OPC 有 3147 個,SpreadsheetML 有 6328 個。數(shù)據(jù)結(jié)構(gòu)十分復雜,通過手工方式編寫這些標簽的結(jié)構(gòu)體效率很低且易出錯,通過 XML 模式來生成文檔對象模型代碼。


          86oG0mHITS.jpeg


          舉一個典型的讀取或創(chuàng)建單元格的例子:坐標為 D2 的單元格值是 Q1,帶有藍色背景色和黑色的實線邊框樣式。下面是處理過程:圖中的這些 XML 的片段來源于目錄中的不同文件,每個 c 標簽代表一個單元格,s 屬性值為 7 代表單元格應用了索引為 7 的樣式,我們?nèi)?styles.xml 當中找到索引為 7 的樣式,通過 xf 標簽的 fontId 和 fillId 屬性可以確定字體 ID 和 單元格填充樣式 ID,borderId 和 applyBorder 屬性對應邊框樣式的定義和邊框是否開啟,numFmtId 是數(shù)字格式相關(guān)的定義。根據(jù)每一個字段向下去找,可以看到字號是 11,字體是 Calibri,包括單元格填充的顏色,顏色如果用到主題色,再去主題索引查找所對應的主題,找到顏色的色值,根據(jù)具體的色值表示方法,需要對色值進行換算。后面是對于邊框的處理,根據(jù)邊框 ID 為 2 找到它的上下左右邊框樣式定義。最后樣式處理完成,到這里我們還沒有看到對單元格值 Q1 的定義,這個圖里沒有體現(xiàn)出 Q1 的實際存儲結(jié)構(gòu)。大家可以看到 v 標簽的值是 0,而不是 Q1 這個字符,由于該單元格的值是字符串類型,不會隨單元格存儲,根據(jù)索引 0 到字典中查找就可以讀到單元格的值了。這個過程涉及到跨多個 XML 文檔的處理,需要對 Excel 文檔內(nèi)部結(jié)構(gòu)比較了解,典型的結(jié)構(gòu)包括:工作簿(Workbook)包含多個工作表(Sheets),工作表包含圖表(Chart)、表格(Table)和數(shù)據(jù)透視表(Pivot table)等,數(shù)據(jù)透視表又包含數(shù)據(jù)透視緩存(Pivot Cache)和數(shù)據(jù)透視記錄(Pivot Records)。另外,工作簿還與主題(Theme)、樣式(Style)、公式計算鏈(Calc Chain)以及共享字符表(Shared Strings)等部分有關(guān)聯(lián)關(guān)系。在了解這些之后就可以實現(xiàn)該技術(shù)標準了,其中涉及累計超過 1 萬個不同的 XML 標簽與屬性。


          kz2LrGosm7.jpeg


          一般來說 XML 文檔的首行會聲明文檔編碼,XML 支持累計 228 種編碼類型,在使用 Go 語言處理非 UTF-8 編碼的XML 文檔時,可以在解析時設置 XML 標準庫的 CharsetReader 為 charset 包的 NewReaderLabel 可以解決絕大多數(shù)常用的文檔編碼,此外也可以使用自定義的字符集轉(zhuǎn)碼函數(shù)進行處理。


          0kGNDQG0s9.jpeg


          對于包含大規(guī)模數(shù)據(jù)的電子表格文檔,使用流式處理可以獲得更好的性能。利用基于事件驅(qū)動的方式進行流式讀取,但對于生成文檔, XML 本身沒有“流式生成”的概念,下面就介紹一下如何用 Go 語言來“流式生成” Excel 文檔。對于一個典型的 Excel 文檔內(nèi)部結(jié)構(gòu):其中包含了開放包裝公約、顯式關(guān)系、隱式關(guān)系等文檔組件,往往數(shù)據(jù)量最大的部分是存儲于工作表中的單元格。Excel 文檔中單元格數(shù)據(jù)結(jié)構(gòu)是什么樣的呢:在每個工作表對應的 XML 中,sheetData 標簽存儲著全部單元格的數(shù)據(jù),內(nèi)部按行進行排布,例如 B2 單元格的值為 123,在行號為 2 的 row 標簽的 c 子標簽中,c 標簽的 r 屬性標記該單元格坐標,單元格的值存儲于 v 子標簽中,該結(jié)構(gòu)構(gòu)成了單元格數(shù)據(jù)結(jié)構(gòu)的最小單元。除此之外在 sheetData 上下文中存儲著其他工作表部件。


          mgrYVMdLwY.jpeg


          “流式寫入”可以避免在創(chuàng)建包含大量單元格工作表過程中文檔對象模型在內(nèi)存中的大量分配,但是需要實現(xiàn)該功能需要維護整個工作表的數(shù)據(jù)狀態(tài),按照行號依次寫入,對于每張工作表有對應的流式寫入器 StreamWriter,其中還要維護支持流式寫入的數(shù)據(jù)結(jié)構(gòu)和上下文信息,例如當前工作表名稱、ID、合并單元格和表格等,在準備對工作表進行流式寫入之前,先初始化流式寫入器,創(chuàng)建對應的緩沖區(qū),當寫入單元格時,根據(jù)單元格的數(shù)據(jù)結(jié)構(gòu)來構(gòu)造字符流寫入緩沖區(qū),為了控制內(nèi)存占用,當緩沖區(qū)大小達到閾值時將會在系統(tǒng)臨時目錄進行磁盤緩存,根據(jù)每個單元格狀態(tài)通過字符串拼接的方式進行流式生成,該過程需確保生成的 XML符合格式標準,一旦拼接出錯將會導致最終保存生成文檔無法被 Excel 程序所正確打開。


          0eFT1LMBZ9.jpeg


          通過 Flush 終止流式寫入進程,首先進行單元格狀態(tài)的處理 sheetData 的標簽是否需要提前關(guān)閉,然后將單元格之外的工作表部件數(shù)據(jù)分段序列化:例如合并單元格、表格等,序列化結(jié)果全部追加寫入緩沖區(qū)完成流式寫入,該設計模式不僅支持流式設置單元格,也可以擴展:支持設置列寬、單元格樣式、流式合并單元格、流式設置表格等,此時工作表的完整數(shù)據(jù)加載至內(nèi)存中,內(nèi)存占用僅為使用文檔對象模型的 10%。


          zGu4Ypy96E.jpeg


          保存工作簿,當保存或另存為工作簿時,依次將各文檔部件序列化寫入 ZIP 包中,同時讀取緩沖區(qū)中的流式寫入數(shù)據(jù)寫入 ZIP 中,完成保存,至此一個完整的工作表生成過程就完成了。需要注意的是這里的流式寫入是對于工作表單元格數(shù)據(jù)、共享字符表等典型的容易產(chǎn)生大規(guī)模數(shù)據(jù)的區(qū)域進行流式生成,而像文檔屬性、主題、數(shù)據(jù)透視表、批注評論、圖表等部分采用文檔對象模型處理則更好。


          mu5DsI8QTT.jpeg

          開源 Excel 文檔基礎庫 Excelize 結(jié)合了以上兩種處理方式,在保障兼容性和性能上做了平衡,生成 10.24 萬行 50 列,每個單元格 6 個字符,累計 512 萬單元格的工作表,對比普通和流式處理模式的性能,通過實測可以看出普通寫入在耗時方面大約是流式生成的 5 倍,內(nèi)存占用是流式寫入的 7 倍。


          電子表格作為大規(guī)模應用復雜 XML 的典型代表,在使用 Go 語言實現(xiàn) Excel 文檔基礎庫過程中,根據(jù)業(yè)務場景選擇合適的處理方式,把其中的技術(shù)原理和應用實踐經(jīng)驗給大家做了分享,其中一些設計和方法除了在辦公文檔領(lǐng)域、也可以在其他領(lǐng)域被泛化應用,希望能夠?qū)τ行枰呐笥延兴鶐椭?/p>


          瀏覽 46
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费麻豆国产一区二区三区四区 | 香蕉成人视频 | 色婷婷综合国产 | 国内精品毛片 | 日韩欧美成人在线 |