ExcelHelper.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using NPOI.HSSF.UserModel;
  9. using NPOI.XSSF.UserModel;
  10. using NPOI.SS.UserModel;
  11. using NPOI.SS.Util;
  12. using YiSha.Util.Extension;
  13. namespace YiSha.Util
  14. {
  15. /// <summary>
  16. /// List导出到Excel文件
  17. /// </summary>
  18. /// <typeparam name="T"></typeparam>
  19. public class ExcelHelper<T> where T : new()
  20. {
  21. #region List导出到Excel文件
  22. /// <summary>
  23. /// List导出到Excel文件
  24. /// </summary>
  25. /// <param name="sFileName"></param>
  26. /// <param name="sHeaderText"></param>
  27. /// <param name="list"></param>
  28. public string ExportToExcel(string sFileName, string sHeaderText, List<T> list, string[] columns)
  29. {
  30. sFileName = string.Format("{0}_{1}", SecurityHelper.GetGuid(), sFileName);
  31. string sRoot = GlobalContext.HostingEnvironment.ContentRootPath;
  32. string partDirectory = string.Format("Resource{0}Export{0}Excel", Path.DirectorySeparatorChar);
  33. string sDirectory = Path.Combine(sRoot, partDirectory);
  34. string sFilePath = Path.Combine(sDirectory, sFileName);
  35. if (!Directory.Exists(sDirectory))
  36. {
  37. Directory.CreateDirectory(sDirectory);
  38. }
  39. using (MemoryStream ms = CreateExportMemoryStream(list, sHeaderText, columns))
  40. {
  41. using (FileStream fs = new FileStream(sFilePath, FileMode.Create, FileAccess.Write))
  42. {
  43. byte[] data = ms.ToArray();
  44. fs.Write(data, 0, data.Length);
  45. fs.Flush();
  46. }
  47. }
  48. return partDirectory + Path.DirectorySeparatorChar + sFileName;
  49. }
  50. /// <summary>
  51. /// List导出到Excel的MemoryStream
  52. /// </summary>
  53. /// <param name="list">数据源</param>
  54. /// <param name="sHeaderText">表头文本</param>
  55. /// <param name="columns">需要导出的属性</param>
  56. private MemoryStream CreateExportMemoryStream(List<T> list, string sHeaderText, string[] columns)
  57. {
  58. HSSFWorkbook workbook = new HSSFWorkbook();
  59. ISheet sheet = workbook.CreateSheet();
  60. Type type = typeof(T);
  61. PropertyInfo[] properties = ReflectionHelper.GetProperties(type, columns);
  62. ICellStyle dateStyle = workbook.CreateCellStyle();
  63. IDataFormat format = workbook.CreateDataFormat();
  64. dateStyle.DataFormat = format.GetFormat("yyyy-MM-dd");
  65. //单元格填充循环外设定单元格格式,避免4000行异常
  66. ICellStyle contentStyle = workbook.CreateCellStyle();
  67. contentStyle.Alignment = HorizontalAlignment.Left;
  68. #region 取得每列的列宽(最大宽度)
  69. int[] arrColWidth = new int[properties.Length];
  70. for (int columnIndex = 0; columnIndex < properties.Length; columnIndex++)
  71. {
  72. //GBK对应的code page是CP936
  73. arrColWidth[columnIndex] = properties[columnIndex].Name.Length;
  74. }
  75. #endregion
  76. for (int rowIndex = 0; rowIndex < list.Count; rowIndex++)
  77. {
  78. #region 新建表,填充表头,填充列头,样式
  79. if (rowIndex == 65535 || rowIndex == 0)
  80. {
  81. if (rowIndex != 0)
  82. {
  83. sheet = workbook.CreateSheet();
  84. }
  85. #region 表头及样式
  86. {
  87. IRow headerRow = sheet.CreateRow(0);
  88. headerRow.HeightInPoints = 25;
  89. headerRow.CreateCell(0).SetCellValue(sHeaderText);
  90. ICellStyle headStyle = workbook.CreateCellStyle();
  91. headStyle.Alignment = HorizontalAlignment.Center;
  92. IFont font = workbook.CreateFont();
  93. font.FontHeightInPoints = 20;
  94. font.Boldweight = 700;
  95. headStyle.SetFont(font);
  96. headerRow.GetCell(0).CellStyle = headStyle;
  97. sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, properties.Length - 1));
  98. }
  99. #endregion
  100. #region 列头及样式
  101. {
  102. IRow headerRow = sheet.CreateRow(1);
  103. ICellStyle headStyle = workbook.CreateCellStyle();
  104. headStyle.Alignment = HorizontalAlignment.Center;
  105. IFont font = workbook.CreateFont();
  106. font.FontHeightInPoints = 10;
  107. font.Boldweight = 700;
  108. headStyle.SetFont(font);
  109. for (int columnIndex = 0; columnIndex < properties.Length; columnIndex++)
  110. {
  111. // 类属性如果有Description就用Description当做列名
  112. DescriptionAttribute customAttribute = (DescriptionAttribute)Attribute.GetCustomAttribute(properties[columnIndex], typeof(DescriptionAttribute));
  113. string description = properties[columnIndex].Name;
  114. if (customAttribute != null)
  115. {
  116. description = customAttribute.Description;
  117. }
  118. headerRow.CreateCell(columnIndex).SetCellValue(description);
  119. headerRow.GetCell(columnIndex).CellStyle = headStyle;
  120. //根据表头设置列宽
  121. sheet.SetColumnWidth(columnIndex, (arrColWidth[columnIndex] + 1) * 256);
  122. }
  123. }
  124. #endregion
  125. }
  126. #endregion
  127. #region 填充内容
  128. IRow dataRow = sheet.CreateRow(rowIndex + 2); // 前面2行已被占用
  129. for (int columnIndex = 0; columnIndex < properties.Length; columnIndex++)
  130. {
  131. ICell newCell = dataRow.CreateCell(columnIndex);
  132. newCell.CellStyle = contentStyle;
  133. string drValue = properties[columnIndex].GetValue(list[rowIndex], null).ParseToString();
  134. //根据单元格内容设定列宽
  135. int length = (System.Text.Encoding.UTF8.GetBytes(drValue).Length+1)*256;
  136. if (sheet.GetColumnWidth(columnIndex) < length && !drValue.IsEmpty())
  137. {
  138. sheet.SetColumnWidth(columnIndex, length);
  139. }
  140. switch (properties[columnIndex].PropertyType.ToString())
  141. {
  142. case "System.String":
  143. newCell.SetCellValue(drValue);
  144. break;
  145. case "System.DateTime":
  146. case "System.Nullable`1[System.DateTime]":
  147. newCell.SetCellValue(drValue.ParseToDateTime());
  148. newCell.CellStyle = dateStyle; //格式化显示
  149. break;
  150. case "System.Boolean":
  151. case "System.Nullable`1[System.Boolean]":
  152. newCell.SetCellValue(drValue.ParseToBool());
  153. break;
  154. case "System.Byte":
  155. case "System.Nullable`1[System.Byte]":
  156. case "System.Int16":
  157. case "System.Nullable`1[System.Int16]":
  158. case "System.Int32":
  159. case "System.Nullable`1[System.Int32]":
  160. newCell.SetCellValue(drValue.ParseToInt());
  161. break;
  162. case "System.Int64":
  163. case "System.Nullable`1[System.Int64]":
  164. newCell.SetCellValue(drValue.ParseToString());
  165. break;
  166. case "System.Double":
  167. case "System.Nullable`1[System.Double]":
  168. newCell.SetCellValue(drValue.ParseToDouble());
  169. break;
  170. case "System.Single":
  171. case "System.Nullable`1[System.Single]":
  172. newCell.SetCellValue(drValue.ParseToDouble());
  173. break;
  174. case "System.Decimal":
  175. case "System.Nullable`1[System.Decimal]":
  176. newCell.SetCellValue(drValue.ParseToDouble());
  177. break;
  178. case "System.DBNull":
  179. newCell.SetCellValue(string.Empty);
  180. break;
  181. default:
  182. newCell.SetCellValue(string.Empty);
  183. break;
  184. }
  185. }
  186. #endregion
  187. }
  188. using (MemoryStream ms = new MemoryStream())
  189. {
  190. workbook.Write(ms);
  191. workbook.Close();
  192. ms.Flush();
  193. ms.Position = 0;
  194. return ms;
  195. }
  196. }
  197. #endregion
  198. #region Excel导入
  199. /// <summary>
  200. /// Excel导入
  201. /// </summary>
  202. /// <param name="filePath"></param>
  203. /// <returns></returns>
  204. public List<T> ImportFromExcel(string filePath)
  205. {
  206. string absoluteFilePath = GlobalContext.HostingEnvironment.ContentRootPath + filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
  207. List<T> list = new List<T>();
  208. HSSFWorkbook hssfWorkbook = null;
  209. XSSFWorkbook xssWorkbook = null;
  210. ISheet sheet = null;
  211. using (FileStream file = new FileStream(absoluteFilePath, FileMode.Open, FileAccess.Read))
  212. {
  213. switch (Path.GetExtension(filePath))
  214. {
  215. case ".xls":
  216. hssfWorkbook = new HSSFWorkbook(file);
  217. sheet = hssfWorkbook.GetSheetAt(0);
  218. break;
  219. case ".xlsx":
  220. xssWorkbook = new XSSFWorkbook(file);
  221. sheet = xssWorkbook.GetSheetAt(0);
  222. break;
  223. default:
  224. throw new Exception("不支持的文件格式");
  225. }
  226. }
  227. IRow columnRow = sheet.GetRow(1); // 第二行为字段名
  228. Dictionary<int, PropertyInfo> mapPropertyInfoDict = new Dictionary<int, PropertyInfo>();
  229. for (int j = 0; j < columnRow.LastCellNum; j++)
  230. {
  231. ICell cell = columnRow.GetCell(j);
  232. PropertyInfo propertyInfo = MapPropertyInfo(cell.ParseToString());
  233. if (propertyInfo != null)
  234. {
  235. mapPropertyInfoDict.Add(j, propertyInfo);
  236. }
  237. }
  238. for (int i = (sheet.FirstRowNum + 2); i <= sheet.LastRowNum; i++)
  239. {
  240. IRow row = sheet.GetRow(i);
  241. T entity = new T();
  242. for (int j = row.FirstCellNum; j < columnRow.LastCellNum; j++)
  243. {
  244. if (mapPropertyInfoDict.ContainsKey(j))
  245. {
  246. if (row.GetCell(j) != null)
  247. {
  248. PropertyInfo propertyInfo = mapPropertyInfoDict[j];
  249. switch (propertyInfo.PropertyType.ToString())
  250. {
  251. case "System.DateTime":
  252. case "System.Nullable`1[System.DateTime]":
  253. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToDateTime());
  254. break;
  255. case "System.Boolean":
  256. case "System.Nullable`1[System.Boolean]":
  257. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToBool());
  258. break;
  259. case "System.Byte":
  260. case "System.Nullable`1[System.Byte]":
  261. mapPropertyInfoDict[j].SetValue(entity, Byte.Parse(row.GetCell(j).ParseToString()));
  262. break;
  263. case "System.Int16":
  264. case "System.Nullable`1[System.Int16]":
  265. mapPropertyInfoDict[j].SetValue(entity, Int16.Parse(row.GetCell(j).ParseToString()));
  266. break;
  267. case "System.Int32":
  268. case "System.Nullable`1[System.Int32]":
  269. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToInt());
  270. break;
  271. case "System.Int64":
  272. case "System.Nullable`1[System.Int64]":
  273. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToLong());
  274. break;
  275. case "System.Double":
  276. case "System.Nullable`1[System.Double]":
  277. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToDouble());
  278. break;
  279. case "System.Single":
  280. case "System.Nullable`1[System.Single]":
  281. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToDouble());
  282. break;
  283. case "System.Decimal":
  284. case "System.Nullable`1[System.Decimal]":
  285. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString().ParseToDecimal());
  286. break;
  287. default:
  288. case "System.String":
  289. mapPropertyInfoDict[j].SetValue(entity, row.GetCell(j).ParseToString());
  290. break;
  291. }
  292. }
  293. }
  294. }
  295. list.Add(entity);
  296. }
  297. hssfWorkbook?.Close();
  298. xssWorkbook?.Close();
  299. return list;
  300. }
  301. /// <summary>
  302. /// 查找Excel列名对应的实体属性
  303. /// </summary>
  304. /// <param name="columnName"></param>
  305. /// <returns></returns>
  306. private PropertyInfo MapPropertyInfo(string columnName)
  307. {
  308. PropertyInfo[] propertyList = ReflectionHelper.GetProperties(typeof(T));
  309. PropertyInfo propertyInfo = propertyList.Where(p => p.Name == columnName).FirstOrDefault();
  310. if (propertyInfo != null)
  311. {
  312. return propertyInfo;
  313. }
  314. else
  315. {
  316. foreach (PropertyInfo tempPropertyInfo in propertyList)
  317. {
  318. DescriptionAttribute[] attributes = (DescriptionAttribute[])tempPropertyInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
  319. if (attributes.Length > 0)
  320. {
  321. if (attributes[0].Description == columnName)
  322. {
  323. return tempPropertyInfo;
  324. }
  325. }
  326. }
  327. }
  328. return null;
  329. }
  330. #endregion
  331. }
  332. }