专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

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

  相信很多人在做项目的都碰到过Excel数据导出的需求,我从最开始使用最原始的HTML拼接(将需要导出的数据拼接成TABLE标签)到后来happy的使用开源的NPOI,EPPlus等开源组件导出EXCEL。
  但不久前,我在一个项目碰到一个需求:要将几个分别有近60多万的数据源导出到Excel中,我们先不要讨论这个需求本身是否合理,客户就是要这样。我先后用NPOI和EPPlus,都发现同一个问题:OutOfMemoryException,我电脑12G内存居然不够用?
  的确内存溢出了,但内存还剩下好几个G的,就会溢出,我用。NET做的网站,开发的时候Host应该是VisualStudio安装的IISExpress,应该是VS本身的限制,不过在网上查阅资料也没发现这的确也是困扰一些人的,也没查到什么结果。
  好在还有Google,跃过墙外,在StackOverflow上查到资料:OpenXML,这不是什么新技:Office2007在设计的时候,为了更好的和其它应用程序交互,使用了XMLZIP技术来实现excel,world,PPT等组件的本地保存,我们所使用xlsx,dox,pptx文件本质上就一个ZIP压缩包,包内是组织好的XML文件,也就是说,我们可以通过生成,修改,生成合规的XML文件,再压缩成ZIP包,这就是一个可以被Office识别的文件了。
  用图说话:
  在园子里其实也有不少人介绍过OpenXML,我想就多一个视角来介绍OpenXML吧,好像也有很长时间没人写关于这个博文。
  什么是OfficeOpenXML?
  我们来看下维基百科的定义:
  OfficeOpenXML(alsoinformallyknownasOOXMLorMicrosoftOpenXML(MOX)〔2)isazipped,XMLbasedfileformatdevelopedbyMicrosoft〔3〕forrepresentingspreadsheets,charts,presentationsandwordprocessingdocuments。TheformatwasinitiallystandardizedbyEcma(asECMA376),andbytheISOandIEC(asISOIEC29500)inlaterversions。
  StartingwithMicrosoftOffice2007,theOfficeOpenXMLfileformatshavebecomethedefault〔4〕targetfileformatofMicrosoftOffice。〔5〕〔6〕MicrosoftOffice2010providesreadsupportforECMA376,readwritesupportforISOIEC29500Transitional,andreadsupportforISOIEC29500Strict。〔7〕MicrosoftOffice2013andMicrosoftOffice2016additionallysupportbothreadingandwritingofISOIEC29500Strict。〔8〕re
  refer:https:en。wikipedia。orgwikiOfficeOpenXML
  从Office2007开始,就开始使用XML文件格式作为MicrosoftOffice的默认保存方式,其实我们通常用的NPOIoffice2007部分和EPPlus就是使用OpenXML来开发的。
  为什么同是使用OpenXML,NPOI和EPPLus会出现内存溢出的问题?
  这两个开源组件有对Office套件有着很全面的支持,它们会把数据加载到内存中一次性处理,如果碰到数据量过大,就很可能遇到这个问题,网上EPPlus在20多万条数据的就溢出了,NPOI在11多万的时候就会溢出,这个是和数据的列数和内容有关系,不管怎样,我们以后可能是会碰到这种大量数据的EXCEL导出,我们不需要很复杂的功能,就是想要导出一个EXCEL列表,这其实是可以做到的。
  OpenXML怎样做不会内存溢出?
  NPOI和EPPlus在导出大量数据的Excel列表时可能会发生内存溢出的问题,原因是它们都把数据保存在内存中,因为它们支持各种复杂的功能,那么简单的列表,就是数量超大,我们把它通过文件流写入磁盘,这个问题就解决了。
  如何使用OPENXML?
  我们需要去微软官网下载OFFICEOPENXML的SDK,链接:https:www。microsoft。comenhkdownloaddetails。aspx?id30425,推荐使用NuGet在VISULALSTUDIO直接将引用添加到Project。
  GitHub示例代码:https:github。comOfficeDevOpenXMLSDK
  代码实现
  说了这么多废话,我们看如何用OPENXML实现一个EXCEL列表的导出:
  从原理上讲就是用OpenXML一个一个把标签写入本地磁盘。
  我截取我写的导出类的几个方法来来解释:
  指定磁盘路径初始化OpenWorkDoucment
  summary
  param
  privatevoidOpenWorkDocument(stringfileName)
  {
  documentSpreadsheetDocument。Create(fileName,SpreadsheetDocumentType。Workbook);
  }
  用datatable作为数据源,实际情况可以根据需要调整
  summary
  publicvoidAddSheet(DataTabledt,stringsheetName)
  {
  if(dtnulldt。Rows。Count0)
  {
  thrownewArgumentNullException(nameof(dt),datasourcecannotbenull);
  }
  if(documentnull)
  {
  thrownewArgumentNullException(nameof(document),pleaseinitdocumentfirst);
  }
  thislistofattributeswillbeusedwhenwritingastartelement
  Listattributes;
  这是我们为什么不会溢出的关键点,使用XmlWriter写入磁盘
  OpenXmlWriterwriter;
  WorksheetPartworkSheetPartdocument。WorkbookPart。AddNewPart();
  writerOpenXmlWriter。Create(workSheetPart);
  使用OpenXML麻烦的地方就是我们要用SDK去拼接XML内容
  writer。WriteStartElement(newWorksheet());
  writer。WriteStartElement(newSheetViews());sheetViews
  writer。WriteStartElement(newSheetView()sheetView
  {
  TabSelectedtrue,
  WorkbookViewId0U这里的下标是从0开始的
  });
  这里是冻结列头,别问为什么是A2,我试了A1不行
  PanepanenewPane()
  {
  StatenewEnumValue(PaneStateValues。Frozen),
  VerticalSplitnewDoubleValue((double)1),
  TopLeftCellnewStringValue(A2),
  ActivePanenewEnumValue(PaneValues。BottomLeft)
  };
  对于一些文档本身的结构的描述,我们可以直接把准备属性设置正确,直接写入,因为描述实例很占用资源小,当然我们也可以把描述结点的子节点,子子节点都通过WriteStartElememt写入,不过很麻烦,容易出错
  writer。WriteStartElement(pane);Pane
  writer。WriteEndElement();Pane
  writer。WriteStartElement(newSelection()
  {
  PanenewEnumValue(PaneValues。BottomLeft)
  });
  writer。WriteEndElement();Selection关闭标签
  writer。WriteEndElement();sheetView关闭标签
  writer。WriteEndElement();sheetViews关闭标签
  writer。WriteStartElement(newSheetData());
  varrowIndex0;
  foreach(DataRowrowindt。Rows)
  {
  buildheader
  if(rowIndex0)
  {
  createanewlistofattributes
  attributesnewList();
  addtherowindexattributetothelist
  attributes。Add(newOpenXmlAttribute(r,null,(rowIndex1)。ToString()));
  headerstart
  writer。WriteStartElement(newRow(),attributes);
  foreach(DataColumncolindt。Columns)
  {
  attributesnewList();
  这里注意,在Excel在处理字符串的时候,会将所有的字符串保存到sharedStrings。xml,cell内写入在sharedString。XML的索引,属性t(type)设置为s(str)我们在导出excel的时候把sharedString。mxl考虑进来会加大复杂程度,所以将t设置为str,一个不存在的type,excel会直接解析cell内的字串值
  attributes。Add(newOpenXmlAttribute(t,null,str));
  通过s指定style样式的下标
  attributes。Add(newOpenXmlAttribute(s,null,FORMATINDEXHEADER。ToString()));
  能过r指定单元格位置,好像不是必需,注意这里下标位置是从1开始的
  attributes。Add(newOpenXmlAttribute(r,,string。Format({0}{1},GetColumnName(col。Ordinal1),rowIndex1)));
  writer。WriteStartElement(newCell(),attributes);
  writer。WriteElement(newCellValue(col。ColumnName));
  writer。WriteEndElement();
  }
  headerend
  writer。WriteEndElement();
  rowIndex;
  }
  数据写入,我们通过xmlWriter不会触发异常createanewlistofattributes
  attributesnewList();
  addtherowindexattributetothelist
  attributes。Add(newOpenXmlAttribute(r,null,(rowIndex1)。ToString()));
  headerstart
  writer。WriteStartElement(newRow(),attributes);
  foreach(DataColumncolindt。Columns)
  {
  attributesnewList();
  switch(col。DataType。ToString())
  {
  caseSystem。Int32:
  attributes。Add(newOpenXmlAttribute(s,null,FORMATINDEXINT。ToString()));
  attributes。Add(newOpenXmlAttribute(t,null,n));number
  break;
  caseSystem。Double:
  caseSystem。Decimal:
  caseSystem。Float:
  attributes。Add(newOpenXmlAttribute(s,null,FORMATINDEXDEC。ToString()));headerstyle
  attributes。Add(newOpenXmlAttribute(t,null,n));number
  break;
  default:
  attributes。Add(newOpenXmlAttribute(s,null,FORMATINDEXSTR。ToString()));headerstyle
  attributes。Add(newOpenXmlAttribute(t,null,str));string
  break;
  }
  addthecellreferenceattribute
  attributes。Add(newOpenXmlAttribute(r,null,string。Format({0}{1},GetColumnName(col。Ordinal1),rowIndex1)));
  writer。WriteStartElement(newCell(),attributes);
  writer。WriteElement(newCellValue(row〔col。Ordinal〕。ToString()));
  writer。WriteEndElement();
  }
  headerend
  writer。WriteEndElement();
  rowIndex;
  }
  EndSheetData
  writer。WriteEndElement();
  EndWorksheet
  writer。WriteEndElement();
  writer。Close();
  if(document。WorkbookPart。Workbooknull)
  {
  document。WorkbookPart。WorkbooknewWorkbook();
  document。WorkbookPart。Workbook。Append(newSheets());
  }
  数据写入完成后,注册一个sheet引用到workbook。xml,也就是在excel最下面的sheetname
  varsheetnewSheet()
  {
  Name!String。IsNullOrWhiteSpace(sheetName)?sheetName:(SheetDateTime。Now。ToString(ms)),
  SheetIdUInt32Value。FromUInt32((uint)msheetIndex),
  Iddocument。WorkbookPart。GetIdOfPart(workSheetPart)
  };
  document。WorkbookPart。Workbook。Sheets。Append(sheet);
  }
  生成Style样式,注意下标从0开始,依次加1,如果有跳过1直接设置3这样情况,可能无法正常解析到样式
  privateStylesheetGenerateStylesheet()
  {
  StylesheetstyleSheetnull;
  FontsfontsnewFonts(
  newFont(Index0default
  newFontSize(){Val11}
  ),
  newFont(Index1header
  newFontSize(){Val11},
  newBold(),
  newColor(){RgbFFFFFF}
  ));
  FillsfillsnewFills(
  newFill(newPatternFill(){PatternTypePatternValues。None}),Index0default
  newFill(newPatternFill(){PatternTypePatternValues。Gray125}),Index1default
  newFill(newPatternFill(newForegroundColor{RgbnewHexBinaryValue(){Value0070c0}}){PatternTypePatternValues。Solid})
  );
  BordersbordersnewBorders(
  newBorder(),index0default
  newBorder(index1blackborder
  newLeftBorder(newColor(){Autotrue}){StyleBorderStyleValues。Thin},
  newRightBorder(newColor(){Autotrue}){StyleBorderStyleValues。Thin},
  newTopBorder(newColor(){Autotrue}){StyleBorderStyleValues。Thin},
  newBottomBorder(newColor(){Autotrue}){StyleBorderStyleValues。Thin},
  newDiagonalBorder())
  );
  NumberingFormatsnumbersnewNumberingFormats(
  newNumberingFormat(){NumberFormatId0,FormatCodenewStringValue(,0。00)},
  newNumberingFormat(){NumberFormatId1,FormatCodenewStringValue(0)}
  );
  CellFormatscellFormatsnewCellFormats(
  default
  newCellFormat(){FormatIdFORMATINDEXDEFUALT},
  bodystring
  newCellFormat{FormatIdFORMATINDEXSTR,FontId0,FillId0,BorderId1,ApplyBordertrue},
  bodydecimal
  newCellFormat{FormatIdFORMATINDEXDEC,FontId0,FillId0,BorderId1,NumberFormatId0,ApplyBordertrue},
  header
  newCellFormat{FormatIdFORMATINDEXHEADER,FontId1,FillId2,BorderId1,ApplyFilltrue},header
  bodyint
  newCellFormat{FormatIdFORMATINDEXINT,FontId0,FillId0,BorderId1,NumberFormatId1,ApplyBordertrue}
  );
  styleSheetnewStylesheet(numbers,fonts,fills,borders,cellFormats);
  returnstyleSheet;
  }
  privatevoidWriteWorkbookStyle()
  {
  if(document!null)
  {
  WorkbookStylesPartstylePartdocument。WorkbookPart。AddNewPart();
  varstyleSheetGenerateStylesheet();
  styleSheet。Save(stylePart);
  }
  }
  设置样式,冻结首行,这些都可以简单完成,如果需要添加图表什么的,还是建议用NPOI,EPPlus等开源方案,有图表的excel不会太大。
  对于OpenXML的介绍就到这里了,有什么错误的地方,请指正。来源:RHINOWU
  cnblogs。comrhinop8283219。html

泰国清迈中国人多吗?多!非常多!多到把我吓坏了。上个月刚回来,说说我的感觉,似乎置身于一个国内有当地方言和文字的省份沟通零障碍!吃惊一一下飞机,手机下载的打车软件grab会自动翻译成中文。从测面反应出抑郁症不吃药能好吗?你好,我是精神科医生,我觉得这种医学问题你应该会判断听谁的话,尤其那些劝你不服药的,我真不想说什么!抑郁症是慢性致残性精神疾病!真正的抑郁症确实有自愈的可能,但是非常小,就像抗癌明餐饮行业如何运用小程序拓客引流?谢悟空邀请!首先,这个问题不是很具体,不是很好回答比如你的餐饮具体的定位,是什么样的餐饮,是小吃,是火锅,是炒菜,还是烧烤等因为具体的定位不同,引流的方法肯定也不同。拿火锅为例新开地球为什么能永恒自转下去?传统的观点认为,太阳和行星皆形成于一团巨大的原始旋转星云物质。当这些原始旋转星云物质在自身引力作用下自行收缩时,由于角动量守恒,星云物质越收缩,越致密,旋转也就越来越快,当星球形成休斯顿世锦赛,孙颖莎会拿女单冠军吗?不好说哦,陈梦,王曼昱都是很有实力的且看教练给力不给力。可能会认为孙颖莎来日方长,先人后己,不必急于求成,未来可期。女单夺冠,只看好王曼昱了,她的教练德才兼备,久经历炼,功勋卓著,毛孔粗大是怎么产生的,有什么办法可以避免吗?毛孔粗大真的很难看,就像拔过毛的鸡一样,而且里面还经常有很多东西堵在毛孔的管道里面。生活中发现毛孔粗大的人,他们大多都有这些习惯存在1抽烟熬夜,有这些习惯的人,毛孔一般比同龄人粗大03年的奔驰S500可以买吗?03年的奔驰S500到今年为止可以说已经有15个年头了,随之而来的产物除了情怀,还有高昂的费用,而且情怀这种东西,也是需要用钱堆砌起来的,所以说买这辆S500之前,需要先预备一笔钱彭镇在什么地方?四川省成都市双流区彭镇。前天我刚去彭镇的观音阁茶馆喝茶了。详细具体的位置,使用导航就可以明确了,用文字说起来又复杂,又不清楚。彭镇始建于明朝,与成都周边的老场镇之一。前天的下午一点湖北武汉的汉口被誉为四大名镇之一,有哪些老街巷值得逛逛的?1洞庭街这是一条穿越古今,别具风情的老街道。它两重分界,横跨英法俄三块租界。洞庭街上还有依街而建的洞庭村。这里有詹天佑的故居巴公房子,如果大家还有印象,会发现人在囧途这部电影就是在住房公积金自己交860公司交860,这样的公司在什么水平?个人和公司住房公积金月缴存额为860元,这样的公司,高于全国平均水平。住房公积金的高低,主要取决于以下2个因素一是缴费基数二是缴费比例。评价住房公积金的水平,重点考虑2个因素一是所为什么银行总是在晚上下班时间,给厂里的员工发放工资?银行每天的交易都是天文数字,尤其是白天,实时到账实时查询等交易占用了银行计算机的大部分计算通讯资源,不能出现延误,要求很高。例如,当从银行账户向证券交易账户转款,不能等上几分钟,在
张廷玉为康熙和雍正帝鞠躬尽瘁,为什么退休了乾隆却要抄他的家?张廷玉是清代康乾盛世的缔造者和参与者之一,是清朝军机处制度的首创者和完善者。但就是这样一位功绩赫赫的三朝元老,却被乾隆帝抄家,数额高达36万两!张廷玉要知道,乾隆继位之初,对贪腐的历史上亚洲有哪些国家从未被欧洲人殖民?在公元16世纪到公元20世纪之间,许多欧洲国家开始征服世界并夺取各个国家的财富。他们夺取北美南美澳大利亚新西兰非洲以及亚洲的土地作为其殖民地,不断地掠夺当地人的财富,疯狂压榨当地居清朝第一贪污大案清代到了乾隆朝中期,开始走向衰落,官员腐败,贪污横行。每当遇到严重自然灾害,地方各级官员常常利用赈济借机大肆进行侵贪。以下是小编精心整理的清朝第一贪污大案,欢迎阅读,希望大家能够喜TPFi7路由器来了新款ArcherBE900配有触摸屏和LED灯,可以显示数据和表情符号等TPLink宣布了一系列基于即将到来的IEEE规范的世界首款WiFi7路由器。该公司正在改造其整个产品线,包iPhone被指狂收集隐私库克回应苹果只需要最少的信息稿源TechWeb11月16日消息,据媒体报道,今日苹果CEO蒂姆?库克在接受采访时谈到了诸多话题,包括iPhone14最新的紧急求救卫星功能等,并且首次就马斯克收购推特表态。据悉国产工业软件龙头国家近期宣布将持续完善国家工业互联网大数据中心建设,支持符合条件的工业物联网软件企业。当前上市公司公司中有哪些工业互联网软件公司呢,我们来梳理一下。1中望软件国内领先的工业软件供应8点1氪丨建行客服回应转账失败腾讯发布2022年三季度财报每日优鲜全职员工仅剩55人上市进行时百果园36氪获悉,16日,港交所文件显示,深圳百果园实业(集团)股份有限公司再次递交港股上市申请。今年5月,百果园曾向港交所提交上市申请书。微导纳米源杰半导体证监会同意江天风证券激光消费设备有望延续强势,新能源半导体设备性价比将逐步体现11月17日消息,天风证券最新研报表示,1短期推荐板块自动化设备,半导体设备其中尤其重视激光消费设备的机会。2重点关注子行业观点1)激光设备顺周期板块,下游地产基建占比高我们认为本特斯拉与尼古拉特斯拉提到特斯拉,所有的人都会联想到电动汽车特斯拉的老板埃隆马斯克。实际上,特斯拉汽车由马丁艾伯哈德和马克塔潘宁于2003创建。他们分别成为公司的首席执行官和首席财务官。通用汽车公司结束入股消金,牵手蚂蚁,传化智联坚定破冰物流数字化一个是B端物流领域的强者,一个是C端金融科技的翘楚。在实体经济和数字化走向融合的大背景下,两个企业的强强联合,会为整个物流行业数字化和智能化发展带来怎样的火花?2022年11月1436氪研究院2022年中国智能仓储行业洞察报告智慧仓储是指使用互联网物联网AI大数据云计算等技术,以用户需求为中心所重构的智能化仓储流程。与传统仓储相比,智能仓储重视核心数据的积累与应用,使用新技术促进仓储各个环节流畅运转,降
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网