使用工具:POI(JAVA),NPOI(.Net)

致谢博主 Crazy_Jeff 提供的思路

一、问题描述:
导出任务数据量近100W甚至更多,导出的项目就会内存溢出,挂掉。

二、原因分析:
1、每个进程在写Excel文件时,都是先将数据加载到内存,然后再将内存里面的数据生成文件;因此单个进程任务的数据量过大,将无法及时回收系统内存,最终导致系统内存耗尽而宕机。
2、导出中查询结果是一次性全部查询出来,占用大量系统内存资源。

三、优化方案思路:
1、将所有导出查询全部改成分页的方式查询;
2、将写Excel文件使用IO流来实现,采用POI,或NPOI拼接xml字符串完成,迭代一批数据就flush进硬盘,同时把list,大对象赋值为空,显式调用垃圾回收器,及时回收内存。
首先提供Java版代码POI实现,来自:https://blog.csdn.net/SirLZF/article/details/47438899

  1. import java.io.File;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.io.OutputStreamWriter;
  8. import java.io.Writer;
  9. import java.lang.reflect.Method;
  10. import java.util.Calendar;
  11. import java.util.Enumeration;
  12. import java.util.HashMap;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.UUID;
  16. import java.util.zip.ZipEntry;
  17. import java.util.zip.ZipFile;
  18. import java.util.zip.ZipOutputStream;
  19.  
  20. import org.apache.poi.ss.usermodel.DateUtil;
  21. import org.apache.poi.ss.usermodel.IndexedColors;
  22. import org.apache.poi.ss.util.CellReference;
  23. import org.apache.poi.xssf.usermodel.XSSFCellStyle;
  24. import org.apache.poi.xssf.usermodel.XSSFDataFormat;
  25. import org.apache.poi.xssf.usermodel.XSSFSheet;
  26. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  27. import org.springframework.beans.factory.annotation.Autowired;
  28. import org.springframework.stereotype.Service;
  29.  
  30. import com.chengfeng.ne.global.service.ITaskService;
  31. import com.thinkjf.core.config.GlobalConfig;
  32.  
  33. /**
  34. * 功能描述:生成Excel文件类
  35. * @author Jeff
  36. * @version 1.0
  37. * @date 2015-08-03
  38. */
  39. @Service("xlsxOutPutService")
  40. public class XlsxOutPutService {
  41. @Autowired
  42. private ITaskService taskService;
  43.  
  44. /**
  45. * 导出每个sheet行数
  46. */
  47. public int pageSize = Integer.parseInt(GlobalConfig
  48. .getPropertyValue("common.exoprt.Worksheet.max.rownum"));
  49.  
  50. /**
  51. * 根据传入的不同serviceName来执行不同的查询语句
  52. * @param serviceName
  53. * @param execMethod
  54. * @param params
  55. * @param pageIndex
  56. * @return
  57. */
  58. public List<?> queryBySerivceName(String serviceName,String execMethod, Map<String, Object> params,int pageIndex)throws Exception{
  59. List<?> resultList = null;
  60. if("taskService".equals(serviceName)){
  61. resultList = taskService.queryExportResultPage(execMethod,params, pageIndex, pageSize);
  62. }
  63. return resultList;
  64. }
  65.  
  66. /**
  67. * 生成Excel文件外部调用方法
  68. * @param headList 标题列表
  69. * @param fieldName 字段列表
  70. * @param sheetName 工作薄sheet名称
  71. * @param tempFilePath 临时文件目录
  72. * @param filePath 目标文件
  73. * @param execMethod 执行sql
  74. * @param params 查询参数
  75. * @param serviceName 执行service方法对象名称
  76. * @throws Exception
  77. */
  78. public void generateExcel(List<String> headList,List<String> fieldName,String sheetName, String tempFilePath,String filePath,String execMethod, Map<String, Object> params,String serviceName)
  79. throws Exception {
  80. XSSFWorkbook wb = new XSSFWorkbook();
  81. Map<String, XSSFCellStyle> styles = createStyles(wb);
  82. XSSFSheet sheet = wb.createSheet(sheetName);
  83. String sheetRef = sheet.getPackagePart().getPartName().getName();
  84. String sheetRefList = sheetRef.substring(1);
  85. File tempFiledir = new File(tempFilePath);
  86. if(!tempFiledir.exists()){
  87. tempFiledir.mkdirs();
  88. }
  89. String uuid = UUID.randomUUID().toString();
  90. uuid = uuid.replace("-", "");
  91.  
  92. File sheetFileList = new File(tempFilePath + "/sheet_" + uuid + ".xml");
  93.  
  94. File tmpFile = new File(tempFilePath + "/"+uuid+".xlsx");
  95. FileOutputStream os = new FileOutputStream(tmpFile);
  96. wb.write(os);
  97. os.close();
  98.  
  99. Writer fw = new OutputStreamWriter(new FileOutputStream(
  100. sheetFileList), "UTF-8");
  101. //生成sheet
  102. generateExcelSheet(headList,fieldName, fw, styles,execMethod,params,serviceName);
  103. fw.close();
  104.  
  105. //将临时文件压缩替换
  106. FileOutputStream out = new FileOutputStream(filePath);
  107. substituteAll(tmpFile, sheetFileList, sheetRefList, out);
  108. out.close();
  109. // 删除临时文件
  110. tmpFile.delete();
  111. sheetFileList.delete();
  112.  
  113. tmpFile = null;
  114. sheetFileList = null;
  115. os = null;
  116. fw = null;
  117. out = null;
  118.  
  119. Runtime.getRuntime().gc();
  120. }
  121.  
  122. /**
  123. * 生成sheet
  124. * @param headList
  125. * @param fields
  126. * @param out
  127. * @param styles
  128. * @param execMethod
  129. * @param params
  130. * @throws Exception
  131. */
  132. private void generateExcelSheet(List<String> headList,List<String> fields,Writer out,
  133. Map<String, XSSFCellStyle> styles,String execMethod, Map<String, Object> params,String serviceName) throws Exception {
  134. XSSFCellStyle stringStyle = styles.get("cell_string");
  135. XSSFCellStyle longStyle = styles.get("cell_long");
  136. XSSFCellStyle doubleStyle = styles.get("cell_double");
  137. XSSFCellStyle dateStyle = styles.get("cell_date");
  138. Calendar calendar = Calendar.getInstance();
  139. SpreadsheetWriter sw = new SpreadsheetWriter(out);
  140.  
  141. sw.beginWorkSheet();
  142. sw.beginSetColWidth();
  143. for (int i = 10, len = headList.size() - 2; i < len; i++) {
  144. sw.setColWidthBeforeSheet(i, 13);
  145. }
  146. sw.setColWidthBeforeSheet(headList.size() - 1, 16);
  147. sw.endSetColWidth();
  148.  
  149. sw.beginSheet();
  150. // 表头
  151. sw.insertRowWithheight(0, headList.size(), 25);
  152. int styleIndex = ((XSSFCellStyle) styles.get("sheet_title")).getIndex();
  153. for (int i = 0, len = headList.size(); i < len; i++) {
  154. sw.createCell(i, headList.get(i), styleIndex);
  155. }
  156. sw.endWithheight();
  157.  
  158. //
  159. int pageIndex = 1;// 查询起始页
  160. Boolean isEnd = false;// 是否是最后一页,循环条件
  161.  
  162. do {// 开始分页查询
  163. // 导出查询改为分页查询方式,替代原有queryExportResult()方法
  164. long startTimne = System.currentTimeMillis();
  165. List<?> dataList = this.queryBySerivceName(serviceName, execMethod, params, pageIndex);
  166. long endTime = System.currentTimeMillis();
  167. System.out.println("查询"+pageIndex+"完成用时="+((endTime-startTimne))+"毫秒");
  168. if (dataList != null && dataList.size() > 0) {
  169. //写方法-------
  170. int cellIndex = 0;
  171. for (int rownum = 1, len = dataList.size() + 1; rownum < len; rownum++) {
  172. cellIndex = 0;
  173. sw.insertRow((pageIndex-1)*pageSize+rownum);
  174. Object data = dataList.get(rownum-1);
  175. Object val = null;
  176. Method fieldMethod = null;
  177. for (int k = 0, len2 = fields.size(); k < len2; k++) {
  178. fieldMethod = (Method) data.getClass().getMethod("get"+ fields.get(k));
  179. fieldMethod.setAccessible(true);// 不进行安全检测
  180. val = fieldMethod.invoke(data);
  181. if(val == null){
  182. sw.createCell(cellIndex,"",stringStyle.getIndex());
  183. }else{
  184. String typeName = fieldMethod.getGenericReturnType().toString();
  185. if (typeName.endsWith("int") || typeName.endsWith("nteger")) {
  186. sw.createCell(cellIndex, (Integer) val,
  187. longStyle.getIndex());
  188. } else if (typeName.endsWith("ong")) {
  189. sw.createCell(cellIndex, (Long) val, longStyle.getIndex());
  190. } else if (typeName.endsWith("ouble")) {
  191. sw.createCell(cellIndex, (Double) val,
  192. doubleStyle.getIndex());
  193. } else if (typeName.endsWith("util.Date")) {
  194. calendar.setTime((java.util.Date) val);
  195. sw.createCell(cellIndex, calendar, dateStyle.getIndex());
  196. } else if (typeName.endsWith("sql.Date")) {
  197. calendar.setTime((java.sql.Date) val);
  198. sw.createCell(cellIndex, calendar, dateStyle.getIndex());
  199. } else {
  200. sw.createCell(cellIndex, val==null?"":val.toString().replace("<", "&lt;").replace(">", "&gt;"),
  201. stringStyle.getIndex());
  202. }
  203. }
  204. cellIndex++;
  205. }
  206. sw.endRow();
  207. if (rownum % 2000 == 0) {
  208. out.flush();
  209. }
  210. }
  211. //------------
  212. isEnd = true;
  213. pageIndex++;
  214. } else {
  215. isEnd = false;
  216. }
  217. dataList = null;
  218. Runtime.getRuntime().gc();
  219. } while (isEnd);
  220.  
  221. sw.endSheet();
  222. // 合并单元格
  223. // sw.beginMergerCell();
  224. // for (int i = 0, len = dataList.size() + 1; i < len; i++) {
  225. // sw.setMergeCell(i, 8, i, 9);
  226. // }
  227. // sw.endMergerCell();
  228. sw.endWorkSheet();
  229. }
  230.  
  231. /**
  232. * 创建Excel样式
  233. * @param wb
  234. * @return
  235. */
  236. private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb) {
  237. Map<String, XSSFCellStyle> stylesMap = new HashMap<String, XSSFCellStyle>();
  238. XSSFDataFormat fmt = wb.createDataFormat();
  239. XSSFCellStyle style = wb.createCellStyle();
  240. style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
  241. style.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
  242. stylesMap.put("cell_string", style);
  243. XSSFCellStyle style2 = wb.createCellStyle();
  244. style2.setDataFormat(fmt.getFormat("0"));
  245. style2.setAlignment(XSSFCellStyle.ALIGN_CENTER);
  246. style2.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
  247. stylesMap.put("cell_long", style2);
  248. XSSFCellStyle style3 = wb.createCellStyle();
  249. style3.setDataFormat(fmt.getFormat("0.00"));
  250. style3.setAlignment(XSSFCellStyle.ALIGN_CENTER);
  251. style3.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
  252. stylesMap.put("cell_double", style3);
  253. XSSFCellStyle style4 = wb.createCellStyle();
  254. style4.setDataFormat(fmt.getFormat("yyyy-MM-dd HH:mm:ss"));
  255. style4.setAlignment(XSSFCellStyle.ALIGN_CENTER);
  256. style4.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
  257. stylesMap.put("cell_date", style4);
  258. XSSFCellStyle style5 = wb.createCellStyle();
  259. style5.setFillForegroundColor(IndexedColors.AQUA.getIndex());
  260. style5.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
  261. style5.setAlignment(XSSFCellStyle.ALIGN_CENTER);
  262. style5.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
  263. stylesMap.put("sheet_title", style5);
  264. return stylesMap;
  265. }
  266.  
  267. /**
  268. * 打包压缩
  269. * @param zipfile
  270. * @param tmpfileList
  271. * @param entryList
  272. * @param out
  273. * @throws IOException
  274. */
  275. private void substituteAll(File zipfile,File tmpfileList,
  276. String entryList, OutputStream out) throws IOException {
  277. ZipFile zip = new ZipFile(zipfile);
  278. ZipOutputStream zos = new ZipOutputStream(out);
  279. @SuppressWarnings("unchecked")
  280. Enumeration<ZipEntry> en = (Enumeration<ZipEntry>)zip.entries();
  281. while (en.hasMoreElements()) {
  282. ZipEntry ze = en.nextElement();
  283. if (!entryList.contains(ze.getName())) {
  284. zos.putNextEntry(new ZipEntry(ze.getName()));
  285. InputStream is = zip.getInputStream(ze);
  286. copyStream(is, zos);
  287. is.close();
  288. is = null;
  289. System.gc();
  290. }
  291. }
  292. InputStream is = null;
  293. zos.putNextEntry(new ZipEntry(entryList));
  294. is = new FileInputStream(tmpfileList);
  295. copyStream(is, zos);
  296. is.close();
  297.  
  298. zos.close();
  299. zip.close();
  300. is = null;
  301. zos = null;
  302. zip = null;
  303. System.gc();
  304. }
  305.  
  306. private static void copyStream(InputStream in, OutputStream out)
  307. throws IOException {
  308. byte[] chunk = new byte[1024*10];
  309. int count;
  310. while ((count = in.read(chunk)) >= 0)
  311. out.write(chunk, 0, count);
  312. }
  313.  
  314. public int getTrueColumnNum(String address) {
  315. address = address.replaceAll("[^a-zA-Z]", "").toLowerCase();
  316. char[] adds = address.toCharArray();
  317. int base = 1;
  318. int total = 0;
  319. for (int i = adds.length - 1; i >= 0; i--) {
  320. total += (adds[i] - 'a' + 1) * base;
  321. base = 26 * base;
  322. }
  323. return total;
  324. }
  325.  
  326. public static class SpreadsheetWriter {
  327. private final Writer _out;
  328. private int _rownum;
  329.  
  330. public SpreadsheetWriter(Writer out) {
  331. this._out = out;
  332. }
  333.  
  334. public void beginWorkSheet() throws IOException {
  335. this._out
  336. .write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");
  337. }
  338.  
  339. public void beginSheet() throws IOException {
  340. this._out.write("<sheetData>\n");
  341. }
  342.  
  343. public void endSheet() throws IOException {
  344. this._out.write("</sheetData>");
  345. // 合并单元格
  346. }
  347.  
  348. public void endWorkSheet() throws IOException {
  349. this._out.write("</worksheet>");
  350. }
  351.  
  352. //插入行 不带高度
  353. public void insertRow(int rownum) throws IOException {
  354. this._out.write("<row r=\"" + (rownum + 1) + "\">\n");
  355. this._rownum = rownum;
  356. }
  357.  
  358. public void endRow() throws IOException {
  359. this._out.write("</row>\n");
  360. }
  361.  
  362. //插入行且设置高度
  363. public void insertRowWithheight(int rownum, int columnNum, double height)
  364. throws IOException {
  365. this._out.write("<row r=\"" + (rownum + 1) + "\" spans=\"1:"
  366. + columnNum + "\" ht=\"" + height
  367. + "\" customHeight=\"1\">\n");
  368. this._rownum = rownum;
  369. }
  370.  
  371. public void endWithheight() throws IOException {
  372. this._out.write("</row>\n");
  373. }
  374.  
  375. public void beginSetColWidth() throws IOException {
  376. this._out.write("<cols>\n");
  377. }
  378.  
  379. // 设置列宽 下标从0开始
  380. public void setColWidthBeforeSheet(int columnIndex, double columnWidth)
  381. throws IOException {
  382. this._out.write("<col min=\"" + (columnIndex + 1) + "\" max=\""
  383. + (columnIndex + 1) + "\" width=\"" + columnWidth
  384. + "\" customWidth=\"1\"/>\n");
  385. }
  386.  
  387. public void endSetColWidth() throws IOException {
  388. this._out.write("</cols>\n");
  389. }
  390.  
  391. public void beginMergerCell() throws IOException {
  392. this._out.write("<mergeCells>\n");
  393. }
  394.  
  395. public void endMergerCell() throws IOException {
  396. this._out.write("</mergeCells>\n");
  397. }
  398.  
  399. // 合并单元格 下标从0开始
  400. public void setMergeCell(int beginColumn, int beginCell, int endColumn,
  401. int endCell) throws IOException {
  402. this._out.write("<mergeCell ref=\"" + getExcelName(beginCell + 1)
  403. + (beginColumn + 1) + ":" + getExcelName(endCell + 1)
  404. + (endColumn + 1) + "\"/>\n");// 列行:列行
  405. }
  406.  
  407. public void createCell(int columnIndex, String value, int styleIndex)
  408. throws IOException {
  409. String ref = new CellReference(this._rownum, columnIndex)
  410. .formatAsString();
  411. this._out.write("<c r=\"" + ref + "\" t=\"inlineStr\"");
  412. if (styleIndex != -1)
  413. this._out.write(" s=\"" + styleIndex + "\"");
  414. this._out.write(">");
  415. this._out.write("<is><t>" + value + "</t></is>");
  416. this._out.write("</c>");
  417. }
  418.  
  419. public void createCell(int columnIndex, String value)
  420. throws IOException {
  421. createCell(columnIndex, value, -1);
  422. }
  423.  
  424. public void createCell(int columnIndex, double value, int styleIndex)
  425. throws IOException {
  426. String ref = new CellReference(this._rownum, columnIndex)
  427. .formatAsString();
  428. this._out.write("<c r=\"" + ref + "\" t=\"n\"");
  429. if (styleIndex != -1)
  430. this._out.write(" s=\"" + styleIndex + "\"");
  431. this._out.write(">");
  432. this._out.write("<v>" + value + "</v>");
  433. this._out.write("</c>");
  434. }
  435.  
  436. public void createCell(int columnIndex, double value)
  437. throws IOException {
  438. createCell(columnIndex, value, -1);
  439. }
  440.  
  441. public void createCell(int columnIndex, Calendar value, int styleIndex)
  442. throws IOException {
  443. createCell(columnIndex, DateUtil.getExcelDate(value, false),
  444. styleIndex);
  445. }
  446.  
  447. //10 进制转26进制
  448. private String getExcelName(int i) {
  449. char[] allChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
  450. StringBuilder sb = new StringBuilder();
  451. while (i > 0) {
  452. sb.append(allChar[i % 26 - 1]);
  453. i /= 26;
  454. }
  455. return sb.reverse().toString();
  456. }
  457. }
  458.  
  459. }

调用方法如下

  1. String tempFilePath = GlobalConfig.getPropertyValue("common.attach.upload_dir") + "/task/tmp/";
  2. //调用新的生成方法
    xlsxOutPutService.generateExcel(Arrays.asList(cellName), fieldName,MessageUtils.getMessage(exportDateType.toString()),tempFilePath, expFilePath, execMethod, params, "taskService");

.net NPOI实现,这里没有使用list对象,而是将list转成了datatable后再来生成execl,支持多sheet操作

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.IO;
  6. using System.Text;
  7. using ICSharpCode.SharpZipLib.Zip;
  8. using NPOI.SS.UserModel;
  9. using NPOI.SS.Util;
  10. using NPOI.XSSF.UserModel;
  1. /// <summary>
  2. /// Xlsx输出
  3. /// editor:571115139@qq.com
  4. /// </summary>
  5. public class XlsxOutputHelper
  6. {
  7. private const int FlushCnt = ;
  8. private static readonly string _tempFilePath = LocalStorge.TempDirectory;
  9. public int TotalCnt = ;
  10. public Action<int> ProgressShow = null;
  11. private readonly string _batchId;
  12. private List<EntryPackage> _sheetFileList = new List<EntryPackage>();
  13. private readonly string _filePath;
  14. private readonly string _tempFile;
  15. private Dictionary<string, XSSFCellStyle> _styles;
  16. public XlsxOutputHelper(string filePath)
  17. {
  18. var ext = Path.GetExtension(filePath);
  19. if (ext != ".xlsx")
  20. {
  21. _filePath = Path.GetFileNameWithoutExtension(filePath) + ".xlsx";
  22. }
  23. else
  24. {
  25. _filePath = filePath;
  26. }
  27. File.Create(_filePath).Close();
  28. _batchId = Guid.NewGuid().ToString("N");
  29. _tempFile = _tempFilePath + "/" + _batchId + ".xlsx";
  30.  
  31. }
  32. public void BeginGenerate(List<string> sheetNames)
  33. {
  34. XSSFWorkbook wb = new XSSFWorkbook();
  35. _styles = CreateStyles(wb);
  36. foreach (var sheetName in sheetNames)
  37. {
  38. wb.CreateSheet(sheetName);
  39. }
  40. using (var os = new FileStream(_tempFile, FileMode.Create, FileAccess.ReadWrite))
  41. {
  42. wb.Write(os);
  43. }
  44. }
  45.  
  46. /// <summary>
  47. /// 生成Excel,多个sheet文件外部调用方法
  48. /// </summary>
  49. /// <param name="headList">标题列表</param>
  50. /// <param name="sheetName">工作薄sheet名称</param>
  51. /// <param name="querySerivce">查询服务</param>
  52. public bool GenerateSheet(List<string> headList, string sheetName, Func<int/*页码*/,int/*数据标识*/, DataPackage/*返回数据*/> querySerivce)
  53. {
  54. if (!File.Exists(_tempFile)) throw new Exception("请先执行BeginGenerate方法");
  55. XSSFWorkbook wb = new XSSFWorkbook(_tempFile);
  56. XSSFSheet sheet = (XSSFSheet)wb.GetSheet(sheetName);
  57. string sheetRef = sheet.GetPackagePart().PartName.Name;
  58. string sheetRefList = sheetRef.Substring();
  59. wb.Close();
  60. if (!Directory.Exists(_tempFilePath))
  61. {
  62. Directory.CreateDirectory(_tempFilePath);
  63. }
  64. string guid = Guid.NewGuid().ToString("N");
  65. string sheetFileListFile = _tempFilePath + "/sheet_" + guid + ".xml";
  66.  
  67. bool isOk = true;
  68. using (var s = File.OpenWrite(sheetFileListFile))
  69. {
  70. using (StreamWriter fw = new StreamWriter(s, Encoding.UTF8))
  71. {
  72. //生成sheet
  73. if (!GenerateExcelSheet(headList, fw, _styles,querySerivce))
  74. {
  75. isOk = false;
  76. }
  77. }
  78.  
  79. }
  80. if (!isOk)
  81. {
  82. FileHelper.DeleteFile(sheetFileListFile);
  83. return false;
  84. }
  85. _sheetFileList.Add(new EntryPackage() { EntryPath = sheetRefList, XmlFile = sheetFileListFile });
  86. return true;
  87. }
  88. /// <summary>
  89. /// 结束生成Excel写入文件到本地
  90. /// </summary>
  91. /// <param name="writefileConsole"></param>
  92. /// <returns></returns>
  93. public bool EndGenerate(Action<string> writefileConsole)
  94. {
  95. if (!File.Exists(_tempFile)) throw new Exception("请先执行BeginGenerate方法");
  96. if (_sheetFileList == null || _sheetFileList.Count == ) return false;
  97. writefileConsole("正在写入文件,请耐心等待....");
  98. //将临时文件压缩替换
  99. using (var output = File.OpenWrite(_filePath))
  100. {
  101. SubstituteAll(_tempFile, _sheetFileList, output);
  102. }
  103. // 删除临时文件
  104. FileHelper.DeleteFile(_tempFile);
  105. foreach (var entryPackage in _sheetFileList)
  106. {
  107. FileHelper.DeleteFile(entryPackage.XmlFile);
  108. }
  109. return true;
  110. }
  111. ///// <summary>
  112. ///// 生成Excel文件外部调用方法
  113. ///// </summary>
  114. ///// <param name="headList">标题列表</param>
  115. ///// <param name="sheetName">工作薄sheet名称</param>
  116. ///// <param name="filePath">目标文件</param>
  117. ///// <param name="writefileConsole">进度输出</param>
  118. //public bool GenerateExcel(List<string> headList, string sheetName, string filePath, Action<string> writefileConsole)
  119. //{
  120. // XSSFWorkbook wb = new XSSFWorkbook();
  121. // Dictionary<string, XSSFCellStyle> styles = CreateStyles(wb);
  122. // XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(sheetName);
  123. // string sheetRef = sheet.GetPackagePart().PartName.Name;
  124. // string sheetRefList = sheetRef.Substring(1);
  125. // if (!Directory.Exists(_tempFilePath))
  126. // {
  127. // Directory.CreateDirectory(_tempFilePath);
  128. // }
  129. // string guid = Guid.NewGuid().ToString("N");
  130. // string sheetFileListFile = _tempFilePath + "/sheet_" + guid + ".xml";
  131. // string tmpFile = _tempFilePath + "/" + guid + ".xlsx";
  132. // using (var os = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite))
  133. // {
  134. // wb.Write(os);
  135. // }
  136. // using (var s = File.OpenWrite(sheetFileListFile))
  137. // {
  138. // using (StreamWriter fw = new StreamWriter(s, Encoding.UTF8))
  139. // {
  140. // //生成sheet
  141. // if (!GenerateExcelSheet(headList, fw, styles))
  142. // {
  143. // return false;
  144. // }
  145. // }
  146.  
  147. // }
  148. // writefileConsole("正在写入文件,请耐心等待....");
  149. // //将临时文件压缩替换
  150. // using (var output = File.OpenWrite(filePath))
  151. // {
  152. // SubstituteAll(tmpFile, sheetFileListFile, sheetRefList, output);
  153. // }
  154. // // 删除临时文件
  155. // File.Delete(tmpFile);
  156. // File.Delete(sheetFileListFile);
  157. // return true;
  158. //}
  159.  
  160. /// <summary>
  161. /// 生成sheet
  162. /// </summary>
  163. /// <param name="headList"></param>
  164. /// <param name="output"></param>
  165. /// <param name="styles"></param>
  166. /// <param name="querySerivce"></param>
  167. private bool GenerateExcelSheet(List<string> headList, StreamWriter output,
  168. Dictionary<string, XSSFCellStyle> styles, Func<int/*页码*/, int/*数据标识*/, DataPackage/*返回数据*/> querySerivce)
  169. {
  170. XSSFCellStyle stringStyle = styles["cell_string"];
  171. XSSFCellStyle longStyle = styles["cell_long"];
  172. XSSFCellStyle doubleStyle = styles["cell_double"];
  173. XSSFCellStyle dateStyle = styles["cell_date"];
  174.  
  175. SpreadsheetWriter sw = new SpreadsheetWriter(output);
  176. int[] arrColWidth = new int[headList.Count];
  177. for (int i = ; i < headList.Count; i++)
  178. {
  179. arrColWidth[i] = Math.Max(Encoding.GetEncoding().GetBytes(headList[i]).Length, );
  180. }
  181.  
  182. sw.BeginWorkSheet();
  183. sw.BeginSetColWidth();
  184. for (int i = ; i < headList.Count; i++)
  185. {
  186. sw.SetColWidthBeforeSheet(i, arrColWidth[i]+);
  187. }
  188. sw.EndSetColWidth();
  189.  
  190. sw.BeginSheet();
  191. // 表头
  192. sw.InsertRowWithheight(, headList.Count, );
  193. int styleIndex = styles["sheet_title"].Index;
  194. for (int i = , len = headList.Count; i < len; i++)
  195. {
  196.  
  197. sw.CreateCell(i, headList[i], styleIndex);
  198. }
  199. sw.EndWithheight();
  200.  
  201. //
  202. int pageIndex = ;// 查询起始页
  203. bool hasNextRow;// 是否还有数据,循环条件
  204. int flag = ;//用于多批数据的处理
  205. int rownum = ;//总行数
  206. do
  207. {// 开始分页查询
  208. // 导出查询改为分页查询方式,替代原有queryExportResult()方法
  209. DataPackage data = querySerivce(pageIndex, flag);
  210. if (!data.IsSucess) return false;
  211. if(flag== || data.Flag==) flag = data.Flag;
  212. if (flag != && flag != data.Flag)
  213. {
  214. flag = data.Flag;
  215. pageIndex = ;
  216. hasNextRow = true;
  217. continue;
  218. }
  219.  
  220. var dt = data.Table;
  221. if (dt != null && dt.Rows.Count > )
  222. {
  223. int cellIndex;
  224.  
  225. foreach (DataRow row in dt.Rows)
  226. {
  227. cellIndex = ;
  228. sw.InsertRow(rownum);
  229. #region 填充内容
  230.  
  231. foreach (DataColumn column in dt.Columns)
  232. {
  233. string drValue = row[column].ToString();
  234. if (drValue.IsNullOrWiteSpace())
  235. {
  236. sw.CreateCell(cellIndex, "", stringStyle.Index);
  237. }
  238. else
  239. {
  240. switch (column.DataType.ToString())
  241. {
  242. case "System.DateTime"://日期类型
  243. DateTime.TryParse(drValue, out DateTime dateV);
  244. sw.CreateCell(cellIndex, dateV, dateStyle.Index);
  245. break;
  246.  
  247. case "System.Int16"://整型
  248. case "System.Int32":
  249. case "System.Int64":
  250. case "System.Byte":
  251. int.TryParse(drValue, out int intV);
  252. sw.CreateCell(cellIndex, intV, longStyle.Index);
  253. break;
  254. case "System.Decimal"://浮点型
  255. case "System.Double":
  256. double.TryParse(drValue, out double doubV);
  257. sw.CreateCell(cellIndex, doubV, doubleStyle.Index);
  258. break;
  259. case "System.DBNull"://空值处理
  260. sw.CreateCell(cellIndex, "", stringStyle.Index);
  261. break;
  262. default:
  263. sw.CreateCell(cellIndex, drValue.Replace("<", "&lt;").Replace(">", "&gt;"),
  264. stringStyle.Index);
  265. break;
  266. }
  267. }
  268. cellIndex++;
  269. }
  270. #endregion
  271.  
  272. sw.EndRow();
  273. if (rownum % FlushCnt == )
  274. {
  275. output.Flush();
  276. }
  277. rownum++;
  278.  
  279. }
  280. ProgressShow?.Invoke(TotalCnt += rownum - );
  281. hasNextRow = true;
  282. pageIndex++;
  283. }
  284. else
  285. {
  286. hasNextRow = false;
  287. }
  288. GC.Collect();
  289. } while (hasNextRow);
  290.  
  291. sw.EndSheet();
  292. sw.EndWorkSheet();
  293. return true;
  294. }
  295.  
  296. /// <summary>
  297. /// 创建Excel样式
  298. /// </summary>
  299. /// <param name="wb"></param>
  300. /// <returns></returns>
  301. private static Dictionary<string, XSSFCellStyle> CreateStyles(XSSFWorkbook wb)
  302. {
  303. Dictionary<string, XSSFCellStyle> stylesMap = new Dictionary<string, XSSFCellStyle>();
  304. IDataFormat fmt = wb.CreateDataFormat();
  305. ICellStyle style = wb.CreateCellStyle();
  306. style.Alignment = HorizontalAlignment.Left;
  307. style.VerticalAlignment = VerticalAlignment.Center;
  308. stylesMap.Add("cell_string", (XSSFCellStyle)style);
  309. ICellStyle style2 = wb.CreateCellStyle();
  310. style2.DataFormat = fmt.GetFormat("");
  311. style2.Alignment = HorizontalAlignment.Center;
  312. style2.VerticalAlignment = VerticalAlignment.Center;
  313. stylesMap.Add("cell_long", (XSSFCellStyle)style2);
  314. ICellStyle style3 = wb.CreateCellStyle();
  315. style3.DataFormat = fmt.GetFormat("");
  316. style3.Alignment = HorizontalAlignment.Center;
  317. style3.VerticalAlignment = VerticalAlignment.Center;
  318. stylesMap.Add("cell_double", (XSSFCellStyle)style3);
  319. ICellStyle style4 = wb.CreateCellStyle();
  320. style4.DataFormat = fmt.GetFormat("yyyy-MM-dd HH:mm");
  321. style4.Alignment = HorizontalAlignment.Center;
  322. style4.VerticalAlignment = VerticalAlignment.Center;
  323. stylesMap.Add("cell_date", (XSSFCellStyle)style4);
  324. ICellStyle style5 = wb.CreateCellStyle();
  325. style5.FillForegroundColor = IndexedColors.Grey25Percent.Index;
  326. style5.FillPattern = FillPattern.SolidForeground;
  327. style5.Alignment = HorizontalAlignment.Center;
  328. style5.VerticalAlignment = VerticalAlignment.Center;
  329. IFont font = wb.CreateFont();
  330. font.FontHeightInPoints = ;
  331. font.Boldweight = ;
  332. style5.SetFont(font);
  333. stylesMap.Add("sheet_title", (XSSFCellStyle)style5);
  334. return stylesMap;
  335. }
  336.  
  337. /// <summary>
  338. /// 打包压缩
  339. /// </summary>
  340. /// <param name="zipfile"></param>
  341. /// <param name="sheetList"></param>
  342. /// <param name="output"></param>
  343. private void SubstituteAll(string zipfile, List<EntryPackage> sheetList, Stream output)
  344. {
  345. using (ZipOutputStream zos = new ZipOutputStream(output))
  346. {
  347. using (ZipFile zip = new ZipFile(zipfile))
  348. {
  349. IEnumerator en = zip.GetEnumerator();
  350. while (en.MoveNext())
  351. {
  352. if (en.Current == null) continue;
  353. ZipEntry ze = (ZipEntry)en.Current;
  354. if (!sheetList.Exists(e => e.EntryPath.Contains(ze.Name)))
  355. {
  356. zos.PutNextEntry(new ZipEntry(ze.Name));
  357. Stream tis = zip.GetInputStream(ze);
  358. var length = ze.Size;
  359. StreamUtils.Copy(tis, zos, null, (position) =>
  360. {
  361. ProgressShow?.Invoke(Convert.ToInt32((position / (length + 0M)) * ));
  362. });
  363. }
  364. }
  365.  
  366. foreach (var sheetEntry in sheetList)
  367. {
  368. zos.PutNextEntry(new ZipEntry(sheetEntry.EntryPath));
  369. using (Stream lis = new FileStream(sheetEntry.XmlFile, FileMode.Open, FileAccess.ReadWrite))
  370. {
  371. var length = lis.Length;
  372. StreamUtils.Copy(lis, zos, null, (position) =>
  373. {
  374. ProgressShow?.Invoke(Convert.ToInt32((position / (length + 0M)) * ));
  375. });
  376. }
  377. }
  378. }
  379. }
  380. }
  381. /// <summary>
  382. /// 打包压缩
  383. /// </summary>
  384. /// <param name="zipfile"></param>
  385. /// <param name="xmlfile"></param>
  386. /// <param name="entryList"></param>
  387. /// <param name="output"></param>
  388. private void SubstituteAll(string zipfile, string xmlfile, string entryList, Stream output)
  389. {
  390. using (ZipOutputStream zos = new ZipOutputStream(output))
  391. {
  392. using (ZipFile zip = new ZipFile(zipfile))
  393. {
  394. IEnumerator en = zip.GetEnumerator();
  395. while (en.MoveNext())
  396. {
  397. if (en.Current == null) continue;
  398. ZipEntry ze = (ZipEntry)en.Current;
  399. if (!entryList.Contains(ze.Name))
  400. {
  401. zos.PutNextEntry(new ZipEntry(ze.Name));
  402. Stream tis = zip.GetInputStream(ze);
  403. var length = ze.Size;
  404. StreamUtils.Copy(tis, zos, null, (position) =>
  405. {
  406. ProgressShow?.Invoke(Convert.ToInt32((position / (length + 0M)) * ));
  407. });
  408. }
  409. }
  410. zos.PutNextEntry(new ZipEntry(entryList));
  411. using (Stream lis = new FileStream(xmlfile, FileMode.Open, FileAccess.ReadWrite))
  412. {
  413. var length = lis.Length;
  414. StreamUtils.Copy(lis, zos, null, (position) =>
  415. {
  416. ProgressShow?.Invoke(Convert.ToInt32((position / (length + 0M)) * ));
  417. });
  418. }
  419. }
  420. }
  421. }
  422.  
  423. public class SpreadsheetWriter
  424. {
  425. private StreamWriter _out;
  426. private int _rownum;
  427.  
  428. public SpreadsheetWriter(StreamWriter output)
  429. {
  430. this._out = output;
  431. }

public void BeginWorkSheet()
 {
 this._out
 .Write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"> <dimension ref=\"A1\"/>"+
 "<sheetViews><sheetView showRuler=\"1\" showOutlineSymbols =\"1\" defaultGridColor =\"1\" colorId =\"64\" zoomScale =\"100\" workbookViewId =\"0\" ></sheetView></sheetViews><sheetFormatPr baseColWidth=\"8\" defaultRowHeight =\"15\" />");
 }

  1. public void BeginSheet()
  2. {
  3. this._out.Write("<sheetData>\n");
  4. }
  5.  
  6. public void EndSheet()
  7. {
  8. this._out.Write("</sheetData>");
  9. // 合并单元格
  10. }
  11.  
  12. public void EndWorkSheet()
  13. {
  14. this._out.Write("</worksheet>");
  15. }
  16.  
  17. //插入行 不带高度
  18. public void InsertRow(int rownum)
  19. {
  20. this._out.Write("<row r=\"" + (rownum + ) + "\">\n");
  21. this._rownum = rownum;
  22. }
  23.  
  24. public void EndRow()
  25. {
  26. this._out.Write("</row>\n");
  27. }
  28.  
  29. //插入行且设置高度
  30. public void InsertRowWithheight(int rownum, int columnNum, double height)
  31.  
  32. {
  33. this._out.Write("<row r=\"" + (rownum + ) + "\" spans=\"1:"
  34. + columnNum + "\" ht=\"" + height
  35. + "\" customHeight=\"1\">\n");
  36. this._rownum = rownum;
  37. }
  38.  
  39. public void EndWithheight()
  40. {
  41. this._out.Write("</row>\n");
  42. }
  43.  
  44. public void BeginSetColWidth()
  45. {
  46. this._out.Write("<cols>\n");
  47. }
  48.  
  49. // 设置列宽 下标从0开始
  50. public void SetColWidthBeforeSheet(int columnIndex, double columnWidth)
  51.  
  52. {
  53. this._out.Write("<col min=\"" + (columnIndex + ) + "\" max=\""
  54. + (columnIndex + ) + "\" width=\"" + columnWidth
  55. + "\" customWidth=\"1\"/>\n");
  56. }
  57.  
  58. public void EndSetColWidth()
  59. {
  60. this._out.Write("</cols>\n");
  61. }
  62.  
  63. public void BeginMergerCell()
  64. {
  65. this._out.Write("<mergeCells>\n");
  66. }
  67.  
  68. public void EndMergerCell()
  69. {
  70. this._out.Write("</mergeCells>\n");
  71. }
  72.  
  73. // 合并单元格 下标从0开始
  74. public void SetMergeCell(int beginColumn, int beginCell, int endColumn,
  75. int endCell)
  76. {
  77. this._out.Write("<mergeCell ref=\"" + GetExcelName(beginCell + )
  78. + (beginColumn + ) + ":" + GetExcelName(endCell + )
  79. + (endColumn + ) + "\"/>\n");// 列行:列行
  80. }
  81.  
  82. public void CreateCell(int columnIndex, string value, int styleIndex)
  83.  
  84. {
  85. string cellref = new CellReference(this._rownum, columnIndex)
  86. .FormatAsString();
  87. this._out.Write("<c r=\"" + cellref + "\" t=\"inlineStr\"");
  88. if (styleIndex != -)
  89. this._out.Write(" s=\"" + styleIndex + "\"");
  90. this._out.Write(">");
  91. this._out.Write("<is><t>" + value + "</t></is>");
  92. this._out.Write("</c>");
  93. }
  94.  
  95. public void CreateCell(int columnIndex, string value)
  96.  
  97. {
  98. CreateCell(columnIndex, value, -);
  99. }
  100.  
  101. public void CreateCell(int columnIndex, double value, int styleIndex)
  102.  
  103. {
  104. string cellref = new CellReference(this._rownum, columnIndex)
  105. .FormatAsString();
  106. this._out.Write("<c r=\"" + cellref + "\" t=\"n\"");
  107. if (styleIndex != -)
  108. this._out.Write(" s=\"" + styleIndex + "\"");
  109. this._out.Write(">");
  110. this._out.Write("<v>" + value + "</v>");
  111. this._out.Write("</c>");
  112. }
  113.  
  114. public void CreateCell(int columnIndex, double value)
  115.  
  116. {
  117. CreateCell(columnIndex, value, -);
  118. }
  119.  
  120. public void CreateCell(int columnIndex, DateTime value, int styleIndex)
  121.  
  122. {
  123. CreateCell(columnIndex, DateUtil.GetExcelDate(value, false),
  124. styleIndex);
  125. }
  126.  
  127. //10 进制转26进制
  128. private string GetExcelName(int i)
  129. {
  130. char[] allChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
  131. List<char> sb = new List<char>();
  132. while (i > )
  133. {
  134. sb.Add(allChar[i % - ]);
  135. i /= ;
  136. }
  137. sb.Reverse();
  138. return string.Join("", sb);
  139. }
  140. }
  141.  
  142. }
  143.  
  144. public class DataPackage
  145. {
  146. public bool IsSucess { get; set; }
  147. /// <summary>
  148. /// 数据标识
  149. /// </summary>
  150. public int Flag { get; set; }
  151. public DataTable Table { get; set; }
  152. public DataPackage(bool isSucess) : this(isSucess, null, )
  153. {
  154. }
  155. public DataPackage(bool isSucess,DataTable table):this(isSucess,table,)
  156. {
  157. }
  158. public DataPackage(bool isSucess, DataTable table,int flag)
  159. {
  160. IsSucess = isSucess;
  161. Table = table;
  162. Flag = flag;
  163. }
  164. }
  165.  
  166. public class EntryPackage
  167. {
  168. public string EntryPath { get; set; }
  169. public string XmlFile { get; set; }
  170. }

单个sheet使用如下

  1. ProgressBar getDataProgress = new ProgressBar();
  2. XlsxOutputHelper xlsxOutput = new XlsxOutputHelper(_options.OutpuFile);
  3.  
  4. //更新进度条
  5. xlsxOutput.ProgressShow = (cnt) => { getDataProgress.Dispaly(Convert.ToInt32((cnt / (total + 0M)) * )); };
  6. xlsxOutput.BeginGenerate(new List<string> { "sheet1"});
  7. AnnoQureyServ annoQurey = new AnnoQureyServ(...param);//打开查询链接
  8. DataPackage QureyService(int pIndex,int flag)
  9. {
  10. if (!annoQurey.GetEntityAnnosDt(pIndex, out DataTable result, ref msg[]))
  11. {
  12. return new DataPackage(false, null);
  13. }
  14. return new DataPackage(true, result);
  15. }
  16. xlsxOutput.TotalCnt = ;
  17. if (!xlsxOutput.GenerateSheet(colNames, "sheet1",QureyService))
  18. {
  19. //导出失败
  20. }
  21. var isOk = xlsxOutput.EndGenerate((endmsg) =>
  22. {
  23. console("");
  24. console(endmsg);
  25. });

多sheet操作,并且一个sheet中需要查询不同数据源的情况下,注意通过pageindex和flag来判断是否在同一个数据源中或者需要切换数据

  1. DataPackage QureyService(int pIndex/*当前数据源查询页码*/, int flag/*当前数据源ID*/)
  2. {
  3. //当前数据源
  4. DckeyValue src;
  5. //下一个数据源
  6. DckeyValue nextSrc;
  7. if (flag == )
  8. {
  9. src= srcList.Skip(curIndex - ).Take().FirstOrDefault();
  10. }
  11. else if (pIndex == )
  12. {
  13. ++curIndex;
  14. src= srcList.Find(f => f.Dkey == flag);
  15. }
  16. else
  17. {
  18. src= srcList.Find(f => f.Dkey == flag);
  19. }
  20. nextSrc= srcList.Skip(curIndex).Take().FirstOrDefault();
  21. if (src == null)
  22. {
  23. if (nextSrc == null) return new DataPackage(true);
  24. return new DataPackage(true, null, nextSrc.Dkey);//读取下一个数据源
  25. }
  26. .......
  27. .....
  28. }

 或者使用poi,SXSSFWorkbook自带的方法,只是创建对象导致效率稍微低点,具体使用方法查看官网

  1. public static void main(String[] args) throws Throwable {
  2. SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
  3. Sheet sh = wb.createSheet();
  4. for(int rownum = 0; rownum < 1000; rownum++){
  5. Row row = sh.createRow(rownum);
  6. for(int cellnum = 0; cellnum < 10; cellnum++){
  7. Cell cell = row.createCell(cellnum);
  8. String address = new CellReference(cell).formatAsString();
  9. cell.setCellValue(address);
  10. }
  11.  
  12. }
  13.  
  14. // Rows with rownum < 900 are flushed and not accessible
  15. for(int rownum = 0; rownum < 900; rownum++){
  16. Assert.assertNull(sh.getRow(rownum));
  17. }
  18.  
  19. // ther last 100 rows are still in memory
  20. for(int rownum = 900; rownum < 1000; rownum++){
  21. Assert.assertNotNull(sh.getRow(rownum));
  22. }
  23.  
  24. FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
  25. wb.write(out);
  26. out.close();
  27.  
  28. // dispose of temporary files backing this workbook on disk
  29. wb.dispose();
  30. }

The next example turns off auto-flushing (windowSize=-1) and the code manually controls how portions of data are written to disk

关于分页的问题,建议在一次连接中完成

 代码测试可用,内存占用很稳定,如果每次分页查询数据量较大的话建议在之后显式调用GC

使用NPOI或POI 导出Excel大数据(百万级以上),导致内存溢出的解决方案(NPOI,POI)的更多相关文章

  1. java 导出Excel 大数据量,自己经验总结!

    出处: http://lyjilu.iteye.com/ 分析导出实现代码,XLSX支持: /** * 生成<span style="white-space: normal; back ...

  2. java中使用poi导出excel表格数据并且可以手动修改导出路径

    在我们开发项目中,很多时候会提出这样的需求:将前端的某某数据以excel表格导出,今天就给大家写一个简单的模板. 这里我们选择使用poi导出excel: 第一步:导入需要的jar包到 lib 文件夹下

  3. 基于C#语言MVC框架NPOI控件导出Excel表数据

    控件bin文件下载地址:https://download.csdn.net/download/u012949335/10610726@{ ViewBag.Title = "dcxx" ...

  4. POI 生成excel(大数据量) SXSSF

    使用POI 的SXSSF (Streaming Usermodel API)生成较大的excel,同时开启压缩 import junit.framework.Assert; import org.ap ...

  5. java 导出Excel 大数据量,自己经验总结!(二)

    在上一次的基础上加上了样式,以及中文列名 package com.tommy.fundation.util; import java.io.OutputStream; import java.util ...

  6. DataTable 数据量大时,导致内存溢出的解决方案

    /// <summary> /// 分解数据表 /// </summary> /// <param name="originalTab">需要分 ...

  7. poi导出excel数据量过大

    问题:使用poi导出excel,数据量过大导致内存溢出 解决思路:1.多sheet导出 2.生成多个excel打包下载 3.生成csv下载 本文使用的是第二个思路,代码如下: poiUtil工具类 p ...

  8. 使用Apache POI导出Excel小结--导出XLS格式文档

    使用Apache POI导出Excel小结 关于使用Apache POI导出Excel我大概会分三篇文章去写 使用Apache POI导出Excel小结--导出XLS格式文档 使用Apache POI ...

  9. 使用POI导出EXCEL工具类并解决导出数据量大的问题

    POI导出工具类 工作中常常会遇到一些图表需要导出的功能,在这里自己写了一个工具类方便以后使用(使用POI实现). 项目依赖 <dependency> <groupId>org ...

随机推荐

  1. PGI 遇到的坑

    以下记录为本人在使用PGI社区版编译器遇到的问题,包含两类问题 1,PGI编译器本身存在你的bug. 2,在其他编译器编译运行没问题,在PGI中出现问题. 版本(18.11社区版) 1,(bug)内置 ...

  2. debian系统安装vsftpd服务端和ftp客户端

    一.服务器安装和配置 1.安装vsftpd.(此处切换到su权限下了.其它用户请使用sudo权限,没有sudo权限的看前面的教程进行安装) apt-get install vsftpd 2.配置vsf ...

  3. 最短路径:Dijkstra算法 C#

    class Program { ; static void Main(string[] args) { Console.WriteLine("各点距离矩阵如下:"); Consol ...

  4. mac 安装photoshop + 破解

    项目开发中毫无疑问会用到图片,一般情况都是UI将图片切好的,只是,有时候项目中少了一张图片或者是改变图片的尺寸之类的问题,这里我们就不需要每次都找UI要图片了,作为程序员这些基础工具的使用,咱们还是要 ...

  5. 获取sql server中自增量之scope_identity(),@@Identity,IDENT_CURRENT的区别

    http://www.lmwlove.com/ac/ID480 在sql server2005,如果要获某个表最新增加的自增量,我们都知道,可以使用COPE_IDENTITY. IDENT_CURRE ...

  6. Spark内核源码解析

    1.spark内核架构常用术语 Application:基于spark程序,包含一个driver program(客户端程序)和多个executeor(线程) Driver Progrom:代表着sp ...

  7. ArcEngine二次开发之提取外包矩

    1.通过ITopologicalOperator接口,此方法适用于需要获得包含几个或多个要素的最小外包矩形 public IEnvelope GetEnvelope(IGeometryCollecti ...

  8. webdriervAPI(操作cookie)

    from  selenium  import  webdriver driver  =  webdriver.Chorme() driver.get("http://www.baidu.co ...

  9. Flash-aware Page Replacement Algorithm

    1.Abstract:(1)字体太乱,单词中有空格(2) FAPRA此名词第一出现时应有“ FAPRA(Flash-aware Page Replacement Algorithm)”说明. 2.in ...

  10. linux 下文件上传的两种工具(XFTP5和Putty之pscp)方式

    一.使用XFTP(,需要先在LINUX上安装启用FTP服务) 然后,在WINDOWS上启动XFPT6客户端,将下载的文件上传至LINUX 指定目录: 二.使用PUTTY软件安装目录下的PSCP命令 1 ...