公司两年前开发了一个项目电子平台,其中有一个模块是"项目问题清单",这个模块主要是让工程师记录项目的问题并跟踪,但是由于很多工程师不能在外网访问和录入表单时不够方便,所以用户提出了采用Excel导入功能。

  这个问题清单主要功能有以下几点:

1.表结构是主从表关系,一个问题对应对个行动计划

2.一个问题中可以插入图片和附件

3.邮件提醒功能

4.允许将问题清单导入和导出(图片和附件必须跟上)

其中,最为纠结的是Excel中插入或导出附件这个功能。

最新的解决方案是用NPOI方式来操作,但是经分析,NPOI仅支持图片的导出,虽然有返回图片的对象,但是不能获取到指定单元格的图片,还有一个就是不支持2007和附件的插入

后来采用了DocumentFormat.OpenXml.dll这个东西。

以下具体讲讲这个中间的过程。

1.用Open Xml SDK 2.0将做好的模板生成代码,对代码分析和封装

说说其中的对象:SharedStringTablePart 共享数据部件

        DrawingsPart 图片部件

        ThemePart  主题部件

        WorkbookStylesPart 样式部件

        WorksheetPart sheet部件

        VmlDrawingPart 绘图对象

        EmbeddedPackagePart 嵌入包部件

2.导出遇到的问题

2.1 导出的图片自动旋转180了,主要修改这段代码 A.Transform2D transform2D = new A.Transform2D()即可;

2.2 附件.pptx次序颠倒,最后一个附件跑到第一个位置了,研究发现有一段是拼接字符串的东东,代码封装如下:

View Code

1 private void GenerateVmlDrawingPart1Content(VmlDrawingPart vmlDrawingPart1, DataTable dt)2         {3             int tmpInt = 1026;//默认种子附件编号4             System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(vmlDrawingPart1.GetStream(System.IO.FileMode.Create), System.Text.Encoding.UTF8);5             StringBuilder str = new StringBuilder();6             str.Append("<xml xmlns:v=\"urn:schemas-microsoft-com:vml\"\r\n xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n <o:shapelayout v:ext=\"edit\">\r\n  <o:idmap v:ext=\"edit\" data=\"1\"/>\r\n </o:shapelayout><v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" o:spt=\"75\"\r\n  o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">\r\n  <v:stroke joinstyle=\"miter\"/>\r\n  <v:formulas>\r\n   <v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>\r\n   <v:f eqn=\"sum @0 1 0\"/>\r\n   <v:f eqn=\"sum 0 0 @1\"/>\r\n   <v:f eqn=\"prod @2 1 2\"/>\r\n   <v:f eqn=\"prod @3 21600 pixelWidth\"/>\r\n   <v:f eqn=\"prod @3 21600 pixelHeight\"/>\r\n   <v:f eqn=\"sum @0 0 1\"/>\r\n   <v:f eqn=\"prod @6 1 2\"/>\r\n   <v:f eqn=\"prod @7 21600 pixelWidth\"/>\r\n   <v:f eqn=\"sum @8 21600 0\"/>\r\n   <v:f eqn=\"prod @7 21600 pixelHeight\"/>\r\n   <v:f eqn=\"sum @10 21600 0\"/>\r\n  </v:formulas>\r\n  <v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>\r\n  <o:lock v:ext=\"edit\" aspectratio=\"t\"/>\r\n </v:shapetype>");7             str.Append("<v:shape id=\"_x0000_s1025\" type=\"#_x0000_t75\" style=\'position:absolute;\r\n  margin-left:215.25pt;margin-top:2.25pt;width:62.25pt;height:39pt;z-index:1\'\r\n  filled=\"t\" fillcolor=\"window [65]\" stroked=\"t\" strokecolor=\"windowText [64]\"\r\n  o:insetmode=\"auto\">\r\n  <v:fill color2=\"window [65]\"/>\r\n  <v:imagedata o:relid=\"rPPT_title\" o:title=\"\"/>\r\n  <x:ClientData ObjectType=\"Pict\">\r\n   <x:SizeWithCells/>\r\n   <x:Anchor>\r\n    4, 3, 0, 3, 4, 86, 0, 55</x:Anchor>\r\n   <x:CF>Pict</x:CF>\r\n  </x:ClientData>\r\n </v:shape>");8             for (int row = 0; row < dt.Rows.Count; row++)9             {10                 if (dt.Rows[row]["FILE_PPTX_PATH"].ToString() != "")11                 {12                     str.AppendFormat("<v:shape id=\"_x0000_s{0}\" type=\"#_x0000_t75\" style=\'position:absolute;\r\n  margin-left:596.25pt;margin-top:{1}pt;width:53.25pt;height:35.25pt;\r\n  z-index:{3}\' filled=\"t\" fillcolor=\"window [65]\" stroked=\"t\" strokecolor=\"windowText [64]\"\r\n  o:insetmode=\"auto\">\r\n  <v:fill color2=\"window [65]\"/>\r\n  <v:imagedata o:relid=\"rPPT_details\" o:title=\"\"/>\r\n  <x:ClientData ObjectType=\"Pict\">\r\n   <x:SizeWithCells/>\r\n   <x:Anchor>\r\n    10, 5, {2}, 5, 10, 76, {2}, 52</x:Anchor>\r\n   <x:CF>Pict</x:CF>\r\n  </x:ClientData>\r\n </v:shape>", tmpInt, (69.75 + (42.75 * row)).ToString(), row + 2, row + 2);13                     tmpInt++;14                 }15             }16             str.Append("</xml>");17             writer.WriteRaw(str.ToString());18             writer.Flush();19             writer.Close();20         }

纠结个的地方 shape id=\"_x0000_s{0}\"和<x:Anchor>\r\n    10, 5, {2}, 5, 10, 76, {2}, 52</x:Anchor>\r\

shape 嵌入的东西是以1025开始的,1026表示第二个...Anchor 记录附件的位置,个人理解左上角是1,3 右下角是5,7(导入的时候要读入该内容,判断是否有附件)

所有的附件采用用同一个图片

3.导入遇到的问题

3.1Excel中的附件无法抓取,后来解析<x:Anchor>这个东西才得以判断当前单元格是否有附件

3.2附件与Uri对应不上,即shape 与Uri 没有直接的关系,后来分析需要这个OleObjects对象

另附上部分代码:

View Code

1     //获取单元格中的值2     private String GetValue(Cell cell, SharedStringTablePart stringTablePart)3     {4         if (cell == null)5         {6             return "";//7         }8         if (cell.ChildElements.Count == 0)9         {10             return "";11         }12         String value = cell.CellValue.InnerText;13         if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))14         {15             value = stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;16         }17         return value;18     }

View Code

1  //Excel抓取图片2     private void ImportImg(WorksheetDrawing dp, string _Embed, string filePath)3     {4         ImagePart ip = dp.DrawingsPart.Parts.Single(c => c.RelationshipId == _Embed).OpenXmlPart as ImagePart;5         //imgExtension = System.IO.Path.GetExtension(ip.Uri.ToString());6         using (Stream stream = ip.GetStream(FileMode.Open, FileAccess.Read))7         {8             //string path = ip.Uri.OriginalString;//图片路径9             using (BinaryReader reader = new BinaryReader(stream))10             {11                 byte[] buffer = new byte[reader.BaseStream.Length];12                 reader.Read(buffer, 0, Convert.ToInt32(buffer.Length));13                 //string base64String = Convert.ToBase64String(buffer);14 15                 using (MemoryStream streamBitmap = new MemoryStream(buffer))16                 {17                     Bitmap bitImage = new Bitmap((Bitmap)System.Drawing.Image.FromStream(streamBitmap));18                     bitImage.Save(filePath, bitImage.RawFormat);19                     bitImage.Dispose();20                     //Bitmap tmpbmp = new Bitmap(bitImage.Width, bitImage.Height);21 //using(Graphics g = Graphics.FromImage(tmpbmp))22 //{23 //g.DrawImage(bitImage, 0, 0);24 //tmpbmp.Save(filePath, bitImage.RawFormat);25 //}26 //bitImage.Dispose();27 //tmpbmp.Dispose();28                 }29             }30         }31     }

View Code

 //是否存在附件    private void IsAttaach(ref EmbeddedPackagePart emb, string rowIndex, string colIndex)    {var item = (from a in lt_Dictionary                    join b in lt_AttachRef on a.Shapeid equals b.Shapeidwhere a.RowIndex == rowIndex && a.ColIndex == colIndexselect new { b.Uri }).SingleOrDefault();if (item != null)        {            emb = item.Uri;        }    }

//Excel中抓取附件    private void ImportPptx(EmbeddedPackagePart Uri, string filePath)    {using (Stream stream = Uri.GetStream(FileMode.Open, FileAccess.Read))        {using (BinaryReader reader = new BinaryReader(stream))            {byte[] buffer = new byte[reader.BaseStream.Length];                reader.Read(buffer, 0, Convert.ToInt32(buffer.Length));

                FileStream fs = new FileStream(filePath, FileMode.Create);                fs.Write(buffer, 0, buffer.Length);                fs.Flush();                fs.Close();            }        }    }

这段是定位分析附件的

View Code

 //将vml文本加载到xml中,获取行列的定位                VmlDrawingPart vml = documentPack.WorkbookPart.WorksheetParts.First().VmlDrawingParts.First();                Stream workbookstr = vml.GetStream();                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();                doc.Load(workbookstr);string[] strArr = doc.InnerText.Replace("\r\n", "|").Replace("Pict", "").Remove(0, 1).Trim().Split('|');

for (int i = 0; i < doc.FirstChild.ChildNodes.Count; i++)                {if (doc.FirstChild.ChildNodes[i].Name == "v:shape")                    {var item = doc.FirstChild.ChildNodes[i];string[] str = item.InnerText.Replace("\r\n", "|").Trim().Split('|')[1].Split(',');                        lt_Dictionary.Add(new DictionaryClass                        {                            Shapeid = item.Attributes["id"].Value.Split('s').Last(),                            ColIndex = str[0].Trim(),                            RowIndex = str[2].Trim()                        });                    }                }

小结:

1.主要用到了附件与Base64String 互转

View Code

        /// <summary>///Author:严智远  Remark:将流填充到ImagePart对象中  Date:2012-02-18/// </summary>/// <param name="imagePart3"></param>        private void GenerateImagePartContent(ImagePart imagePart, string filePath)        {//将图片转换成字符            System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(HttpContext.Current.Server.MapPath("~")+filePath);            MemoryStream stream = new MemoryStream();            bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);            stream.Position = 0;byte[] buff = new byte[stream.Length];            stream.Read(buff, 0, (int)stream.Length);            stream.Close();

            System.IO.Stream data = GetBinaryDataStream(System.Convert.ToBase64String(buff, 0, buff.Length));            imagePart.FeedData(data);            data.Close();        }

2.IO操作、linq操作对象

3..vml后缀文件的了解

4.如何查看及分析问题

转载于:https://www.cnblogs.com/yanzhiyuan928/archive/2012/03/09/2387784.html

项目总结【Excel中附件导出和导入】相关推荐

  1. .net excel导入mysql_.NET Core使用NPOI将Excel中的数据批量导入到MySQL - 追逐时光者 - 博客园...

    前言: 在之前的几篇博客中写过.NET Core使用NPOI导出Word和Excel的文章,今天把同样我们日常开发中比较常用的使用Excel导入数据到MySQL数据库中的文章给安排上.与此同时还把NP ...

  2. matlab如何在word中插入多个表格,怎么把excel中的数据批量导入到word中的表格中《不同表格间的数据导入》...

    如何将excel表格中大量数据导入matlab中并作图 工具:MATLAB.office excel 将待导入的矩阵结构据录入Excel中,录入时注意行列原矩阵一一对应. 录入完以后保存数据,为了后续 ...

  3. word录入表单数据 java 导入系统,java导入excel | 怎么把excel中的数据批量导入到word中的表格中...

    用javascript怎么实现把excel中的数据批量导入到数据库表中 这个js不能直接实现吧 我们程序用到 先读取excel内容转换成数组 然后放到页面上 再提交表单 储存 MySql如何批量添加数 ...

  4. matlab输入excel高版本,『matlab读取excel指定列』excel中大量数据如何导入matlab当中?超过1000个数据无法一个一个输入...

    如何将excel表格中大量数据导入matlab中并作图 哈哈,选我吧!使用xlsread函数体的语法你在帮助里面搜索xlsread就可以了.我要是现在回答也接翻译帮助文件.xlsread的参数有文件表 ...

  5. 如何在ex表格导入php_怎么使用php把表格中的数据导入到excel中,php如何快速导入excel表格数据...

    php怎么导入大量数据的excel php导出数据的Excel: PHP从数据库分多次读取100万行记录,和分将100万入文本文件都没问题 Excel可以支100万行记录,Excel 2003最大支持 ...

  6. excel中联系人转换为csv导入手机出现乱码的解决方法

    解决方式可直接调至文末黑体加粗加大字号. 同事要举行一个培训会议,需要联系各单位的人员,但是所有人员的单位.姓名.手机号都是存在excel里的.一个个存入手机太麻烦,数量太多会累死人.于是找我帮忙.. ...

  7. ISA Server 2004 中的导出、导入和备份功能

    Microsoft Internet Security and Acceleration (ISA) Server 2004 包含导出和导入功能,您可使用这一功能将 ISA Server 配置参数保存 ...

  8. Excel中 使用链接 批量导入图片

    ■前言 我之前看到很多使用VBA方式导入图片的. 今天发现,使用复制链接这种方式,也可以导入图片. ■导入方法 <table><img src="C:\MyPicture\ ...

  9. poi导出excel中附件超链接

    记录一下 参考了一些博客 https://blog.csdn.net/oTianKongLan123/article/details/106903234 https://blog.csdn.net/s ...

  10. MySQL导入Excel报1406_关于mysql 导入excel 中 数据不全或导入不了的 处理办法(工具sqlyong)借鉴经验...

    文章作者:姜南(Slyar)文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作. 之前发了<表达式变量批量替换器 batchSQL>这篇文章,有童鞋说导入 ...

最新文章

  1. 病虫害模型算法_基于深度学习的目标检测算法综述
  2. 【 English 】与个人品质有关的英语词汇
  3. nodejs如何实现ajax,nodejs使用静态服务器处理ajax
  4. android 学习随笔十六(广播 )
  5. pyqt生成 android,PyQt on Android
  6. jlabel字怎么变化_疫情在家烦躁不如学习怎样练好字吧
  7. Java关键字finally
  8. C# 根据年、月、周、星期获得日期等
  9. JNI开发笔记(五)--JNI语法总结
  10. 使用Forms验证存储用户自定义信息
  11. request的获取路径用法小结
  12. windows7系统适合哪个python_windows7如何下载python系统
  13. 大型网吧网络系统设计详细方案(转)
  14. 王欣复出后的第一款产品
  15. python 如何匹配一撇字符_使用Python正则表达式解析斜杠和撇号
  16. C++:应用有限差分法求解随时间变化 平流方程 ut = - c * ux 在一个空间维度上,与 恒定速度,使用FTCS方法,正向时间差, 居中空间差(附完整源码)
  17. 技术周刊(第10期):新技术又来了?
  18. 生产力、商业价值和敏捷
  19. 李笑来,那个一顿饭点8条鲈鱼的人
  20. 三星S9勃艮第红如何为女人打造“第四维”魅力?

热门文章

  1. xmlhttp上传文件(转贴)
  2. 大过年的,程序员在家改bug…
  3. 全中国加油:Github 开源了新型肺炎防疫项目,一起助力
  4. 李彦宏笑称跟马云同场压力大,马云:压根不知你在场
  5. 2018 开发者生态报告:Java 最流行,Go 最有潜力,JavaScript最常用
  6. 给程序员的10条建议,吐血推荐!
  7. 一名微博架构师的2016年终总结
  8. 再谈如何成为一名优秀CTO
  9. 其实,我是靠怼产品上位的。。。
  10. shell基础之exit,break,continue