最近開發一個功能,從excel中批量導入數據到數據庫中,而excel中的內容中包含圖片。如果沒有包含圖片的話,只是純文本信息,網上已經有很多例子,我就不寫了。我想寫的是,讀取excel中每行特定列的的圖片。
Excel 2007文件 如下:
把該excel文件的后綴名(xlsx)改成zip 或者rnr,我把它改成zip,解壓后你就會發現,excel也就是多個xml文件組成的,所以,很顯然,我們只解析xml文件,就能找到圖片了。
解壓后的excel文件如下:
Excel中的圖片信息都在文件夾xl里面,點擊進去就可以看到以下內容:
圖片就保存在media這個文件夾里面,而獲取圖片要解析的xml,在drawings文件夾里面,所以當要解析xml獲取圖片信息時,可以通過判斷drawings文件夾或者media 文件夾存不存在,來控制程序的執行。如果excel中不存在其中的一個,表明excel中是不存在圖片的,都是文本信息。
圖1
media文件夾中存放着excel的圖片,只是名字按添加的順序依次改為image1、image2……,如果添加的圖片相同的話,meida只保存一個,excel會判斷名字添加的圖片名字相同不。這里強調一下,excel中的圖片信息的位置關系,是按照在excel中插入圖片的順序排列的,並不是按照行號來排列,以為圖片和單元格沒有附屬關系、依附關系。
3.解析drawings文件夾的xml。drawings文件夾中包含drawing1.xml 和_rels文件夾。
drawings.xml 在瀏覽器中的xml代碼如下(直接把這個文件拖到瀏覽器中就可以看到),我們只看一張圖片的,每一張圖片以xdr:twoCellAnchor標簽分隔開。
只截取有用的xml信息,如圖所示:
圖2
然后在看看_rels文件夾中的drawing1.xml.rels的xml信息。如下圖所示:
圖3
從上面三張圖中,我們不難發現一些規則,以下一一解釋:
圖1是media文件夾,是存圖片的。
圖2是drawings.xml,是存圖片在excel中的位置等信息。<xdr:from>這個標簽和<xdr:to> 是對應的,這兩個標簽中都有 <xdr:col>和<xdr:row>,col也就是colum(列),而row(行);<xdr:from>表示圖片從第幾行第幾列 <xdr:to>到 第幾行第幾列,也就是圖片在excel中的覆蓋范圍。這個例子是圖片只能保存在一個單元格內,所以只取from里面的row就知道該圖片屬於哪行了,列都是固定的(Picutre)。在看看row和col的數字,跟excel中的對比一下,在xml中,row和col索引都是從0開始的。
再看<xdr:blipFill>下的子節點<xdr:blipFill>中的<a:blip r:embed="rId1"/>,和圖3對比一下,就可以知道圖片存在哪個文件夾下的哪種圖片。
以上是思路,實現代碼如下:
把excel文件復制一份,並把后綴名改成zip,可以通過File.Copy()函數實現
string oriFile = @"D:\picture.xlsx"; string destFile = @"D:\picture.zip"; File.Copy(oriFile,destFile,true);
解壓picture.zip文件
using ICSharpCode.SharpZipLib.Zip; //這個類庫可以去下載。
string err = ""; /// <summary> /// 功能:解壓zip格式的文件。 /// </summary> /// <param name="zipFilePath">壓縮文件路徑</param> /// <param name="unZipDir">解壓文件存放路徑,為空時默認與壓縮文件同一級目錄下,跟壓縮文件同名的文件夾</param> /// <param name="err">出錯信息</param> /// <returns>解壓是否成功</returns> public static bool UnZipFile(string zipFilePath, string unZipDir, out string err) { err = ""; if (zipFilePath == string.Empty) { err = "壓縮文件不能為空!"; return false; } if (!File.Exists(zipFilePath)) { err = "壓縮文件不存在!"; return false; } //解壓文件夾為空時默認與壓縮文件同一級目錄下,跟壓縮文件同名的文件夾 if (unZipDir == string.Empty) unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath)); if (!unZipDir.EndsWith("//")) unZipDir += "//"; if (!Directory.Exists(unZipDir)) Directory.CreateDirectory(unZipDir); try { using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath))) { ZipEntry theEntry; while ((theEntry = s.GetNextEntry()) != null) { string directoryName = Path.GetDirectoryName(theEntry.Name); string fileName = Path.GetFileName(theEntry.Name); if (directoryName.Length > 0) { Directory.CreateDirectory(unZipDir + directoryName); } if (!directoryName.EndsWith("//")) directoryName += "//"; if (fileName != String.Empty) { using (FileStream streamWriter = File.Create(unZipDir + theEntry.Name)) { int size = 2048; byte[] data = new byte[2048]; while (true) { size = s.Read(data, 0, data.Length); if (size > 0) { streamWriter.Write(data, 0, size); } else { break; } } } } }//while } } catch (Exception ex) { err = ex.Message; return false; } return true; }
解析Xml
string XMLExcelPath = @"D:\picture\xl\drawings\drawing1.xml";Dictionary<string, string> picRowDictionary = new Dictionary<string, string>();//保存行號和圖片的屬性rId private void FromXMLBtn_Click(object sender, EventArgs e) { XmlDocument xdoc = new XmlDocument(); xdoc.Load(XMLExcelPath); //獲取根節點 XmlNode root = xdoc.DocumentElement; //獲取根節點下的所有子節點 XmlNodeList nodeList = root.ChildNodes; //循環遍歷每一個子節點 foreach (XmlNode nl in nodeList) { XmlElement sondNode = (XmlElement)nl; XmlNodeList descendDodeList = sondNode.ChildNodes; XmlNodeList fromNodeList = descendDodeList[0].ChildNodes; //取得行號 string row = fromNodeList.Item(2).InnerText.Trim(); XmlNodeList picNodeList = descendDodeList[2].ChildNodes; XmlNodeList blipFillNodeList = picNodeList[1].ChildNodes; XmlElement picElement =(XmlElement)blipFillNodeList.Item(0); string picturePath = picElement.GetAttribute("r:embed").ToString(); picRowDictionary.Add(row,picturePath); } GetPicture(picRowDictionary); } //獲取圖片,並把圖片copy出來 string pictPath = @"D:\picture\xl\drawings\_rels\drawing1.xml.rels"; string dir = @"D:\picture\xl"; string pathOfPicture = string.Empty; Dictionary<string,string> rowAndNewPicPath=new Dictionary<string,string>(); public Dictionary<string,string> GetPicture (Dictionary<string,string> dic) { if (dic.Count <= 0) return null; XmlDocument doc = new XmlDocument(); doc.Load(pictPath); XmlNode root = doc.DocumentElement; XmlNodeList nlist = root.ChildNodes; foreach (KeyValuePair<string, string> kvp in dic) { foreach(XmlNode xn in nlist) { XmlElement xe = (XmlElement)xn; if (xe.GetAttribute("Id").ToString() == kvp.Value) { pathOfPicture = xe.GetAttribute("Target").ToString().Replace("..","").Replace("/",@"\"); pathOfPicture = dir + pathOfPicture; CopyPicture(kvp.Key,pathOfPicture,rowAndNewPicPath); break; } } } return rowAndNewPicPath; } //根據路徑獲取圖片 public void CopyPicture(string row,string path,Dictionary<string, string> d) { string name=Path.GetFileNameWithoutExtension(path); if (!Directory.Exists(@"D:\resource")) { Directory.CreateDirectory(@"D:\resource"); } File.Copy(path,@"D:\resource\"+name+".jpg",true); d.Add(row,@"D:\rosource\"+name+".jpg"); }