范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

。NET使用OfficeOpenXML导出大量数据到Excel

  相信很多人在做项目的都碰到过Excel数据导出的需求,我从最开始使用最原始的HTML拼接(将需要导出的数据拼接成TABLE标签)到后来happy的使用开源的NPOI, EPPlus等开源组件导出EXCEL。
  但不久前,我在一个项目碰到一个需求:要将几个分别有近60多万的数据源导出到Excel中,我们先不要讨论这个需求本身是否合理,客户就是要这样。我先后用NPOI和EPPlus,都发现同一个问题:OutOfMemoryException,我电脑12G内存居然不够用?
  的确内存溢出了,但内存还剩下好几个G的,就会溢出,我用 .NET做的网站,开发的时候Host应该是Visual Studio安装的IIS Express, 应该是VS本身的限制,不过在网上查阅资料也没发现这的确也是困扰一些人的,也没查到什么结果。
  好在还有Google, 跃过墙外,在Stack Overflow上查到资料: OpenXML , 这不是什么新技: Office 2007在设计的时候, 为了更好的和其它应用程序交互,使用了XML + ZIP技术来实现excel, world, PPT等组件的本地保存, 我们所使用xlsx, dox, pptx文件本质上就一个ZIP压缩包,包内是组织好的XML文件,也就是说,我们可以通过生成, 修改, 生成合规的XML文件,再压缩成ZIP包,这就是一个可以被Office识别的文件了。
  用图说话:
  在园子里其实也有不少人介绍过 Open XML, 我想就多一个视角来介绍Open XML吧,好像也有很长时间没人写关于这个博文。
  什么是Office Open XML?
  我们来看下维基百科的定义:
  Office Open XML (also informally known as OOXML or Microsoft Open XML (MOX)[2) is a zipped, XML-based file format developed by Microsoft[3] for representing spreadsheets, charts, presentations and word processing documents. The format was initially standardized by Ecma (as ECMA-376), and by the ISO and IEC (as ISO/IEC 29500) in later versions.
  Starting with Microsoft Office 2007, the Office Open XML file formats have become the default[4] target file format of Microsoft Office.[5][6] Microsoft Office 2010 provides read support for ECMA-376, read/write support for ISO/IEC 29500 Transitional, and read support for ISO/IEC 29500 Strict.[7] Microsoft Office 2013 and Microsoft Office 2016 additionally support both reading and writing of ISO/IEC 29500 Strict.[8]re
  refer: https://en.wikipedia.org/wiki/Office_Open_XML
  从Office 2007开始,就开始使用XML文件格式作为Microsoft Office的默认保存方式,其实我们通常用的NPOI office 2007部分和EPPlus就是使用Open XML来开发的。
  为什么同是使用Open XML, NPOI和EPPLus会出现内存溢出的问题?
  这两个开源组件有对Office套件有着很全面的支持,它们会把数据加载到内存中一次性处理,如果碰到数据量过大,就很可能 遇到这个问题,网上EPPlus在20多万条数据的就溢出了,NPOI在11多万的时候就会溢出, 这个是和数据的列数和内容有关系,不管怎样,我们以后可能是会碰到这种大量数据的EXCEL导出,我们不需要很复杂的功能,就是想要导出一个EXCEL列表,这其实是可以做到的。
  Open XML怎样做不会内存溢出?
  NPOI和EPPlus在导出大量数据 的Excel列表时可能 会发生内存溢出的问题,原因是它们都把数据保存在内存中,因为它们支持各种复杂的功能,那么简单的列表,就是数量超大,我们把它通过文件流写入磁盘,这个问题就解决了。
  如何使用OPEN XML?
  我们需要去微软官网下载OFFICE OPEN XML的SDK,链接: https://www.microsoft.com/en-hk/download/details.aspx?id=30425,推荐使用NuGet在VISULAL STUDIO直接将引用添加到Project。
  GitHub示例代码:https://github.com/OfficeDev/Open-XML-SDK
  代码实现
  说了这么多废话,我们看如何用OPEN XML实现一个EXCEL列表的导出:
  从原理上讲就是用OpenXML一个一个把标签写入本地磁盘。
  我截取我写的导出类的几个方法来来解释:
  ///
  /// 指定磁盘路径初始化OpenWorkDoucment
  /// 
  /// 
  private void OpenWorkDocument(string fileName)
  {
  document = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook);
  }
  ///
  ///用datatable作为数据源,实际情况可以根据需要调整
  ///
  public void AddSheet(DataTable dt, string sheetName)
  {
  if (dt == null || dt.Rows.Count == 0)
  {
  throw new ArgumentNullException(nameof(dt), "data source can not be null");
  }
  if (document == null)
  {
  throw new ArgumentNullException(nameof(document), "please init document first");
  }
  //this list of attributes will be used when writing a start element
  List attributes;
  //这是我们为什么不会溢出的关键点, 使用XmlWriter写入磁盘
  OpenXmlWriter writer;
  WorksheetPart workSheetPart = document.WorkbookPart.AddNewPart();
  writer = OpenXmlWriter.Create(workSheetPart);
   //使用OpenXML麻烦的地方就是我们要用SDK去拼接XML内容
  writer.WriteStartElement(new Worksheet());
  writer.WriteStartElement(new SheetViews()); //sheetViews
  writer.WriteStartElement(new SheetView() //sheetView
  {
  TabSelected = true,
  WorkbookViewId = 0U //这里的下标是从0开始的
  });
   //这里是冻结列头,别问为什么是A2,我试了A1不行
  Pane pane = new Pane()
  {
  State = new EnumValue(PaneStateValues.Frozen),
  VerticalSplit = new DoubleValue((double)1),
  TopLeftCell = new StringValue("A2"),
  ActivePane = new EnumValue(PaneValues.BottomLeft)
  };
  //对于一些文档本身的结构的描述,我们可以直接把准备属性设置正确,直接写入,因为描述实例很占用资源小,当然我们也可以把描述结点的子节点,子子节点都通过WriteStartElememt写入,不过很麻烦,容易出错
  writer.WriteStartElement(pane); //Pane
  writer.WriteEndElement(); //Pane
  writer.WriteStartElement(new Selection()
  {
  Pane = new EnumValue(PaneValues.BottomLeft)
  });
  writer.WriteEndElement(); //Selection 关闭标签
  writer.WriteEndElement(); //sheetView 关闭标签
  writer.WriteEndElement(); //sheetViews 关闭标签
  writer.WriteStartElement(new SheetData());
  var rowIndex = 0;
  foreach (DataRow row in dt.Rows)
  {
  //build header
  if (rowIndex == 0)
  {
  //create a new list of attributes
  attributes = new List();
  // add the row index attribute to the list
  attributes.Add(new OpenXmlAttribute("r", null, (rowIndex + 1).ToString()));
  //header start
  writer.WriteStartElement(new Row(), attributes);
  foreach (DataColumn col in dt.Columns)
  {
  attributes = new List();
  //这里注意,在Excel在处理字符串的时候,会将所有的字符串保存到sharedStrings.xml, cell内写入在sharedString.XML的索引, 属性t(type)设置为s(str)//我们在导出excel的时候把sharedString.mxl考虑进来会加大复杂程度,所以将t设置为str, 一个不存在的type, excel会直接解析cell内的字串值
  attributes.Add(new OpenXmlAttribute("t", null, "str"));
  //通过s指定style样式的下标
  attributes.Add(new OpenXmlAttribute("s", null, FORMAT_INDEX_HEADER.ToString()));
  //能过r指定单元格位置,好像不是必需, 注意这里下标位置是从1开始的
  attributes.Add(new OpenXmlAttribute("r", "", string.Format("{0}{1}", GetColumnName(col.Ordinal + 1), rowIndex + 1)));
  writer.WriteStartElement(new Cell(), attributes);
  writer.WriteElement(new CellValue(col.ColumnName));
  writer.WriteEndElement();
  }
  //header end
  writer.WriteEndElement();
  rowIndex++;
  }
  //数据写入,我们通过xmlWriter不会触发异常//create a new list of attributes
  attributes = new List();
  // add the row index attribute to the list
  attributes.Add(new OpenXmlAttribute("r", null, (rowIndex + 1).ToString()));
  //header start
  writer.WriteStartElement(new Row(), attributes);
  foreach (DataColumn col in dt.Columns)
  {
  attributes = new List();
  switch (col.DataType.ToString())
  {
  case "System.Int32":
  attributes.Add(new OpenXmlAttribute("s", null, FORMAT_INDEX_INT.ToString()));
  attributes.Add(new OpenXmlAttribute("t", null, "n")); //number
  break;
  case "System.Double":
  case "System.Decimal":
  case "System.Float":
  attributes.Add(new OpenXmlAttribute("s", null, FORMAT_INDEX_DEC.ToString())); //header style
  attributes.Add(new OpenXmlAttribute("t", null, "n")); //number
  break;
  default:
  attributes.Add(new OpenXmlAttribute("s", null, FORMAT_INDEX_STR.ToString())); //header style
  attributes.Add(new OpenXmlAttribute("t", null, "str")); //string
  break;
  }
  //add the cell reference attribute
  attributes.Add(new OpenXmlAttribute("r", null, string.Format("{0}{1}", GetColumnName(col.Ordinal + 1), rowIndex + 1)));
  writer.WriteStartElement(new Cell(), attributes);
  writer.WriteElement(new CellValue(row[col.Ordinal].ToString()));
  writer.WriteEndElement();
  }
  //header end
  writer.WriteEndElement();
  rowIndex++;
  }
  // End SheetData
  writer.WriteEndElement();
  // End Worksheet
  writer.WriteEndElement();
  writer.Close();
  if (document.WorkbookPart.Workbook == null)
  {
  document.WorkbookPart.Workbook = new Workbook();
  document.WorkbookPart.Workbook.Append(new Sheets());
  }
  //数据写入完成后,注册一个sheet引用到workbook.xml, 也就是在excel最下面的sheet name
  var sheet = new Sheet()
  {
  Name = !String.IsNullOrWhiteSpace(sheetName) ? sheetName : ("Sheet " + DateTime.Now.ToString("ms")),
  SheetId = UInt32Value.FromUInt32((uint)m_sheetIndex++),
  Id = document.WorkbookPart.GetIdOfPart(workSheetPart)
  };
  document.WorkbookPart.Workbook.Sheets.Append(sheet);
  }
  //生成Style样式, 注意下标从0开始, 依次加1, 如果有跳过1直接设置3这样情况, 可能无法正常解析到样式
  private Stylesheet GenerateStylesheet()
  {
  Stylesheet styleSheet = null;
  Fonts fonts = new Fonts(
  new Font( // Index 0 - default
  new FontSize() { Val = 11 }
  ),
  new Font( // Index 1 - header
  new FontSize() { Val = 11 },
  new Bold(),
  new Color() { Rgb = "FFFFFF" }
  ));
  Fills fills = new Fills(
  new Fill(new PatternFill() { PatternType = PatternValues.None }), // Index 0 - default
  new Fill(new PatternFill() { PatternType = PatternValues.Gray125 }), // Index 1 - default
  new Fill(new PatternFill(new ForegroundColor { Rgb = new HexBinaryValue() { Value = "0070c0" } }) { PatternType = PatternValues.Solid })
  );
  Borders borders = new Borders(
  new Border(), // index 0 default
  new Border( // index 1 black border
  new LeftBorder(new Color() { Auto = true }) { Style = BorderStyleValues.Thin },
  new RightBorder(new Color() { Auto = true }) { Style = BorderStyleValues.Thin },
  new TopBorder(new Color() { Auto = true }) { Style = BorderStyleValues.Thin },
  new BottomBorder(new Color() { Auto = true }) { Style = BorderStyleValues.Thin },
  new DiagonalBorder())
  );
  NumberingFormats numbers = new NumberingFormats(
  new NumberingFormat() { NumberFormatId = 0, FormatCode = new StringValue("#,##0.00") },
  new NumberingFormat() { NumberFormatId = 1, FormatCode = new StringValue("0") }
  );
  CellFormats cellFormats = new CellFormats(
  // default
  new CellFormat() { FormatId = FORMAT_INDEX_DEFUALT },
  // body string
  new CellFormat { FormatId = FORMAT_INDEX_STR, FontId = 0, FillId = 0, BorderId = 1, ApplyBorder = true },
  // body decimal
  new CellFormat { FormatId = FORMAT_INDEX_DEC, FontId = 0, FillId = 0, BorderId = 1, NumberFormatId = 0, ApplyBorder = true },
  //header
  new CellFormat { FormatId = FORMAT_INDEX_HEADER, FontId = 1, FillId = 2, BorderId = 1, ApplyFill = true }, // header
  // body int
  new CellFormat { FormatId = FORMAT_INDEX_INT, FontId = 0, FillId = 0, BorderId = 1, NumberFormatId = 1, ApplyBorder = true }
  );
  styleSheet = new Stylesheet(numbers, fonts, fills, borders, cellFormats);
  return styleSheet;
  }  
  private void WriteWorkbookStyle()
  {
  if (document != null)
  {
  WorkbookStylesPart stylePart = document.WorkbookPart.AddNewPart();
  var styleSheet = GenerateStylesheet();
  styleSheet.Save(stylePart);
  }
  }
  设置样式,冻结首行,这些都可以简单完成,如果需要添加图表什么的,还是建议用NPOI, EPPlus等开源方案,有图表的excel不会太大。
  对于Open XML的介绍就到这里了,有什么错误的地方,请指正。来源:RHINO_WU
  cnblogs.com/rhino/p/8283219.html

酒店大堂经理一个月工资是多少钱?首先该问题比较笼统,没有明确区域城市酒店类型等信息,只是泛泛的对这个职位的薪酬问询,所以回答起来很难有针对性,本人就从酒店行业的整体来给您分析解答吧。近年来,国家经济进入转型期,从哪款护肤品补水效果超级好?有什么推荐?皮肤缺水会造成干燥,甚至会导致水油不平衡,干皮变油,油皮变干,严重的还会长痘痘。痘痘肌除了内分泌问题,还有一个重要的原因就是皮肤水油不平衡。再者肌肤缺水极容易长出小细纹,长期缺水甚涂抹眼霜时,是拍还是涂呢?两者的效果有什么差别?随着年龄增长,眼睛周围的细纹也越来越明显了,这成为了爱美姑娘们美貌的头号敌人。就连20岁的姑娘们都开始关心自己是不是该用眼霜了?因此,涂抹手法是拍呢还是涂呢成了姑娘们必须了解的知识千元机哪款比较好用?一千左右的手机,既要打游戏,又要看视频,游戏性能取决于手机的处理器,看视频取决于大屏和刷新率,我推荐RealmeQ2。RealmeQ2采用的是联发科天玑800U,7nm工艺制程,L肾阴虚者要阴阳双补还是只补肾阴?严格意义上说,目前市面上流通的中成药绝大多数都是阴阳双补。任何一种中药都有两面性,单纯补阴或是单纯补阳都是不现实的。在实际治疗过程中,如果单独补阴或单独补阳只会使症状加重,对病情并那些被电信诈骗的人,后来怎么样了?我说说我自己吧,深受其害。被杀猪盘网络投资诈骗后近半个月的生活状态犹如行尸走肉,真的一点不夸张,被骗走的不仅仅是多年的积蓄,还有自己对别人的善良和信任。无法接受现实,回忆分析来龙去没有正式工作的人可以买养老社保吗?没有正式工作的人可以买养老社保吗?当然可以,我国社会养老保障制度建设的主旨就是力争实现全民养老,为各类人员设计了多层次,广覆盖的参保方式,没有正式工作的人,也是可以买养老保险的。只一个岗位是长白班,但工资在6000左右,另一个是两班倒,工资在8000左右,该怎么选择?我就是高分子专业的学生,我们很多的学长都在化工厂上班,四班两倒,我的一位直系学长去工作一年了,工资达到了1万,也有学长,长白班,做橡胶研发,工资5000左右,怎么说呢,其实看个人吧儿童补脑长高吃什么?儿童补脑长高吃什么?儿童补脑长高建议吃一些富含蛋白质和维生素的食物,有助于大脑和骨骼的发育。高蛋白质饮食,尤其是动物蛋白质,如瘦肉禽蛋牛奶鱼类乳制品等,还有钙磷维生素等无机盐类食物dota中冰蛙删除了哪些曾经非常逆天的技能?你怎么看?dota不断发展历久弥新,很多曾经非常逆天的技能也消失在历史的长河之中。沉默遗言光环dota1远古版本中沉默面前无连招!他的三技能遗言是被动技能,900范围内当有英雄释放技能后会被世乒赛女单八强出炉,陈梦能挡住王曼昱吗?王艺迪是黑马吗?女单八强出炉后,陈梦与王曼昱会师上半区半决赛概率很大。至于说陈梦能否战胜王曼昱,个人认为目前两人的胜负比为46或者4。55。5的样子,陈梦即便击败王曼昱恐怕也要用7局来实现,而王曼
山东11名低调学霸走红,直接被保送清北,来自于省内7所高中文艾小贝爱教育山东省内有11名低调学霸,被保送清北。高考对于学生们而言,是一场能够改变人生轨迹的人生大考,是学生们必须要考好的,如果学生没有在高考这一考验中,交上一份合格的答卷。那福建舰就位!1艘能顶几艘山东舰?美航母不敢再横行进入6月中旬,除了国际局势出现变化,俄乌冲突激战依旧之外,中国技术再次响彻全球,17日003型国产航母下水,美西方重新审视中国影响力,代表着中国海军跨入三航母时代,003成为全球常他携8吨黄金和3个姨太逃往美国,后挥霍一空,晚年想回家遭到拒绝1933年的中国,东北三省热河地区都已经被日本侵占,而红军也面临着第五次反围剿的失败,队伍和根据地都遭受了重大损失,此时的中华大地,是一片极其恍惚混乱的土地。而那时候的宁夏地区,虽老三下水举欢庆我国科技定能行美帝添堵逞威风看咱反击更强硬2022年6月17号值得中国人民庆祝的日子,咱们的航母老三下水了。我国自主研发建造的舷号18福建舰003号航母正式下水,中国向强大的现代化海军又迈出坚实的一步。满载排水量8万余吨电1977年,山东姑娘捡到一块特大钻石,上交后轰动全国,后来咋样了假设你是一个家庭一般,只会种地的普通人,如果你在机缘巧合之下,突然捡到了一块价值连城的钻石,你会怎么做呢?是会把它独吞,让自己的家庭从此翻身变成富贵人家,还是上交给国家呢?在197提气!三个角度看福建号上的三条标语,越看越有味道标语三条标语红底白字,清清楚楚,明明白白。实现党在新时代的强军目标,把人民军队全面建设成世界一流军队努力建设一支强大的现代化海军,为实现中国梦强军梦提供坚强力量支撑加快构建产业结构姑娘,你可能没有听懂,是让你把行李放上去这么高级吗?自动旋转,但是路人怎么看路标呢?一个一个都是大神啊!这车技但是好像开出去了来量个体温,量不到,把头发波拉起来冒着大雪,顶着寒风也要坐席,只要能吃,啥都不是问题烤榴莲吗?海贼王1053话情报萨博没有死,小丑巴基出手相救,成为新四皇海贼王1053话汉化版已经更新,这一话的内容太劲爆了,新世界迎来大变动,四皇凯多和大妈双双倒台,新四皇呼之欲出,分别是红发香克斯,黑胡子帝奇,草帽小子,小丑巴基。新闻大王摩根斯已经2019年,河南农村小伙张超娶非洲姑娘为妻,如今怎么样了?2018年,河南农村小伙张超到非洲国家津巴布韦打工,期间,他和当地黑人女孩裴心相识并相恋。2019年,张超将裴心带回到了河南农村老家,之后不久,两人便领了结婚证,正式结为了夫妻。值姑娘,你这衣服确实很个性,但拔罐了还是穿严实点吧,哈哈哈哈家里养的猫咪小小年纪就是我惹不起的样子为什么鸠摩智不觊觎降龙十八掌呢有养猫的吗谁知道这究竟是怎么回事呢走自己的路让别人无路可走都说是自助了为什么还要罚款呢右边是放飞的天使左边是脱手洗米华最新状况曝光!涉及金额高达8000亿港币,将于9月份审理洗米华(周焯华)已经入狱长达半年多的时间,这期间虽然有各种消息传出,但都是关于公司以及债务等方面的事情,至于他本人什么时候开审,涉及到多少金额,以及将要获刑多少年,都没有公布。6月