溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

.net 2.0下的OOXML神器:NPOI.OpenXml4Net

發(fā)布時間:2020-07-15 04:54:09 來源:網(wǎng)絡(luò) 閱讀:2636 作者:瞿杰 欄目:編程語言

作者:Tony Qu

NPOI官方博客:http://tonyqus.sinaapp.com | 官方QQ群:189925337

 

可能很多人已經(jīng)習(xí)慣了使用.Net 3.0下的System.IO.Packaging(WindowsBase.dll)來操作Office 2007/2010的文件格式,以至于大家都默許了.net 2.0下無法操作OOXML文件的觀點,盡管也有人使用第三方zip類庫來操作OOXML文件,但是遇到關(guān)系維護之類的問題,就開始糾結(jié)了,你必須自己去不斷地維護.rels文件(OOXML中用于維護文件內(nèi)關(guān)系的文件,這里不是后綴名,這個文件就叫這個名字。),而且文件的內(nèi)容越復(fù)雜,關(guān)系維護就越痛苦。盡管微軟出了OpenXml SDK 2.0,但是很遺憾,這套庫也是基于.net 3.0的。當(dāng)然,我倒不是.net 3.0的堅決反對者,只是出于部署方面的考慮,要知道目前基于.net 2.0的應(yīng)用還是占據(jù)相當(dāng)一部分份額的,盡管.net 3.0/3.5出來也3年了,但是相對于.net 2.0而言,只能算剛剛起步,這也是NPOI始終堅持.net 2.0版本為主線版本的原因。

有人可能要說,.net 3.0/3.5不也是基于.net 2.0的嗎?話是這么說,但是部署起來,還是要單獨部署.net 3.0包,不是嗎?相當(dāng)于額外增加一套庫,就拿我目前的公司來說,我們?nèi)匀辉谟胿s2005開發(fā),服務(wù)器上也只部署了.net 2.0 framework。

.net 2.0下的OOXML神器:NPOI.OpenXml4Net

poi中有一個庫叫OpenXml4j,由Julien Chable于2008年捐贈給POI項目,主要負責(zé)OOXML基礎(chǔ)操作,如創(chuàng)建、讀取、修改、關(guān)系維護等。最近NPOI團隊完成了OpenXml4j的移植工作,于是就有了NPOI.OpenXml4Net,該組件將包括在NPOI下一個版本中,目前你可以通過googlecode的svn獲得完整代碼,自行在本地編譯。OpenXml4Net使用SharpZip作為底層zip操作庫,而非Ionic.Zip,主要原因是SharpZip的設(shè)計與java中的zip庫更接近,移植相對簡單,所以我們選擇了這條捷徑。不過有一點要向大家說明,OpenXml4Net僅負責(zé)底層操作,比如創(chuàng)建部件、創(chuàng)建關(guān)系等,但不包括Office上層的功能,如創(chuàng)建xlsx文件、添加單元格等,這只是一個底層操作庫,NPOI將在后續(xù)版本中陸續(xù)增加,Excel 2007, Word 2007, PowerPoint 2007對應(yīng)的命名空間分別是NPOI.XSSF, NPOI.XWPF, NPOI.XLSF,NPOI.XSSF按計劃將在半年內(nèi)完成(預(yù)計在2012年6月或7月發(fā)布),這次隨本文發(fā)布的算是社區(qū)預(yù)覽版,你可以基于這個版本給我們提建議和bug。

從頭創(chuàng)建OOXML文件

任何一個OOXML都是一個zip文件,在本例中為了方便打開,我們直接使用.zip作為新建文件的擴展名。

//create ooxml file in memory
Package p = Package.Create();

//create package parts
PackagePartName pn1=new PackagePartName(new Uri("/a/abcd/e",UriKind.Relative),true);
if (!p.ContainPart(pn1))
    p.CreatePart(pn1, MediaTypeNames.Text.Plain);

PackagePartName pn2 = new PackagePartName(new Uri("/b/test.xml", UriKind.Relative), true);
if (!p.ContainPart(pn2))
    p.CreatePart(pn2, MediaTypeNames.Text.Xml);

//save file 
p.Save("test.zip");

//don't forget to close it
p.Close();

這里我們創(chuàng)建了2個部件,分別是位于/a/abcd目錄下的e,和位于/b目錄下的test.xml。這里有幾點值得注意:

a. Package.Create有好幾種調(diào)用方式,其中一種是上面這種Package.Create(),這樣最直接的好處就是可以在內(nèi)存中創(chuàng)建文件;而Package.Create(path),即事先傳入文件名,直接在文件系統(tǒng)上創(chuàng)建文件,不用MemoryStream。當(dāng)然啦,對于大文件(超過100M)以上的文件,使用Packakge.Create()做會占用較多的內(nèi)存,所以如果并發(fā)量很高的話,建議慎用。

b. 用了p.ContainPart來判斷節(jié)點是否已經(jīng)存在,盡管對于新創(chuàng)建的文件這么做意義不大,但是這是個好習(xí)慣。

c. 創(chuàng)建PackagePartName的時候,Uri必須是Relative類型的,所以要傳UriKind.Relative。這一點.Net做的比較挫,默認Uri都是Absolute的,而且一旦Uri為Relative類型的,基本上調(diào)用任何Uri的屬性全部會拋異常,這實現(xiàn)夠坑爹的。

 

修改已存在的OOXML文件,并保存為新文件

修改已存在的文件也很簡單,Package.Open就可以了,但由于最后要保存,務(wù)必傳入PackageAccess.READ_WRITE,否則會拋異常。

//create ooxml file in memory
Package p = Package.Open("test.zip",PackageAccess.READ_WRITE);
//create package parts
PackagePartName pn3 = new PackagePartName(new Uri("/c.xml", UriKind.Relative), true);
if (!p.ContainPart(pn3))
    p.CreatePart(pn3, MediaTypeNames.Text.Xml);

//save file 
p.Save("test1.zip");

//don't forget to close it
p.Close();

對于已存在的文件,目前仍然有個bug,那就是不能直接保存為當(dāng)前文件名,存在文件被占用的問題,我們將嘗試在正式版中解決這個問題。

 

目前我們?nèi)匀辉趯penXml4Net接口進行調(diào)整,以提高組件的易用性和穩(wěn)定性。如果大家發(fā)現(xiàn)啥bug或者問題,請直接通過郵件聯(lián)系我。

下載NPOI.OpenXML4Net請到這里:http://code.google.com/p/npoi/downloads/list

OpenXML4Net的源代碼請通過googlecode svn獲取

 

今年NPOI計劃出一本入門級指導(dǎo)書,名字未定,主要面向NPOI初學(xué)者,也可以作為NPOI功能速查手冊,幫助更多的人上手。有興趣的出版社可以通過.net 2.0下的OOXML神器:NPOI.OpenXml4Net聯(lián)系我。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI