ExportDgvToExcel.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. using NPOI.HSSF.UserModel;
  2. using NPOI.SS.UserModel;
  3. using NPOI.XSSF.UserModel;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Data;
  7. using System.Diagnostics;
  8. using System.IO;
  9. using System.Runtime.InteropServices;
  10. using System.Text;
  11. using System.Windows.Forms;
  12. namespace WWPipeLine.Commons
  13. {
  14. public class ExportDgvToExcel
  15. {
  16. /// <summary>
  17. /// CANCELRESULTSTRING = "Cancel"
  18. /// </summary>
  19. public static readonly string CANCELRESULTSTRING = "Cancel";
  20. public static string ExportExcel(string path, DataGridView[] dgvs, string fontname, short fontsize)
  21. {
  22. var msg = string.Empty;
  23. foreach (var dgv in dgvs)
  24. {
  25. var name = string.Empty;
  26. if (dgv.DataSource is DataTable dt)
  27. name = dt.TableName;
  28. else
  29. {
  30. name = dgv.Name + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff");
  31. }
  32. name = name.Replace("#", "-");
  33. name += ".xls";
  34. msg += ExportExcel(path + "\\" + name, dgv, fontname, fontsize);
  35. msg += Environment.NewLine;
  36. }
  37. return msg;
  38. }
  39. #region NPOI DataGridView 导出 EXCEL
  40. /// <summary>
  41. /// NPOI DataGridView 导出 EXCEL
  42. /// <para>03版Excel-xls最大行数是65536行,最大列数是256列</para>
  43. /// <para> 07版Excel-xlsx最大行数是1048576行,最大列数是16384列</para>
  44. /// </summary>
  45. /// <param name="fileName">默认保存文件名</param>
  46. /// <param name="dgv">DataGridView</param>
  47. /// <param name="fontname">字体名称</param>
  48. /// <param name="fontsize">字体大小</param>
  49. public static string ExportExcel(string fileName, DataGridView dgv, string fontname = "雅黑", short fontsize = 12)
  50. {
  51. IWorkbook workbook;
  52. ISheet sheet;
  53. //判断datagridview中内容是否为空
  54. if (dgv.Rows.Count == 0)
  55. {
  56. return ("DataGridView中内容为空!");
  57. }
  58. //保存文件
  59. string saveFileName = "";
  60. SaveFileDialog saveFileDialog = new SaveFileDialog
  61. {
  62. DefaultExt = "xls",
  63. Filter = "Excel文件(*.xls)|*.xls|Excel文件(*.xlsx)|*.xlsx",
  64. RestoreDirectory = true,
  65. Title = "Excel文件保存路径",
  66. FileName = fileName
  67. };
  68. MemoryStream ms = new MemoryStream(); //MemoryStream
  69. if (string.IsNullOrEmpty(fileName))
  70. {
  71. if (saveFileDialog.ShowDialog() == DialogResult.OK)
  72. {
  73. saveFileName = saveFileDialog.FileName;
  74. }
  75. else
  76. {
  77. ms.Close();
  78. ms.Dispose();
  79. return CANCELRESULTSTRING;
  80. }
  81. }
  82. else
  83. {
  84. saveFileName = fileName;
  85. }
  86. //**程序开始计时**//
  87. Stopwatch sw = new Stopwatch();
  88. sw.Start();
  89. //检测文件是否被占用
  90. if (!CheckFiles(saveFileName))
  91. {
  92. ms.Close();
  93. ms.Dispose();
  94. return "文件被占用,请关闭文件";
  95. }
  96. //*** 根据扩展名xls和xlsx来创建对象
  97. string fileExt = Path.GetExtension(saveFileName).ToLower();
  98. if (fileExt == ".xlsx")
  99. {
  100. workbook = new XSSFWorkbook();
  101. }
  102. else
  103. {
  104. workbook = new HSSFWorkbook();
  105. }
  106. //***
  107. //创建Sheet
  108. if (workbook != null)
  109. {
  110. sheet = workbook.CreateSheet("Sheet1");//Sheet的名称
  111. }
  112. else
  113. {
  114. return "未知错误";
  115. }
  116. //设置单元格样式
  117. ICellStyle cellStyle = workbook.CreateCellStyle();
  118. //水平居中对齐和垂直居中对齐
  119. cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
  120. cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
  121. //设置字体
  122. IFont font = workbook.CreateFont();
  123. font.FontName = fontname;//字体名称
  124. font.FontHeightInPoints = fontsize;//字号
  125. font.Color = NPOI.HSSF.Util.HSSFColor.Black.Index;//字体颜色
  126. cellStyle.SetFont(font);
  127. //添加列名
  128. IRow headRow = sheet.CreateRow(0);
  129. var cIndex = 0;
  130. Dictionary<int, int> columnsVisiable = new Dictionary<int, int>();
  131. foreach (DataGridViewColumn column in dgv.Columns)
  132. {
  133. if (!column.Visible) continue;
  134. headRow.CreateCell(cIndex).SetCellValue(column.HeaderText);
  135. headRow.GetCell(cIndex).CellStyle = cellStyle;
  136. columnsVisiable.Add(cIndex, dgv.Columns.IndexOf(column));
  137. cIndex++;
  138. }
  139. //根据类型写入内容
  140. for (int rowNum = 0; rowNum < dgv.Rows.Count; rowNum++)
  141. {
  142. ///跳过第一行,第一行为列名
  143. IRow dataRow = sheet.CreateRow(rowNum + 1);
  144. foreach (int columnIndex in columnsVisiable.Keys)
  145. {
  146. int columnNum = columnsVisiable[columnIndex];
  147. int columnWidth = sheet.GetColumnWidth(columnNum) / 256; //列宽
  148. //隐藏行列不导出
  149. if (dgv.Rows[rowNum].Visible == true && dgv.Columns[columnNum].Visible == true)
  150. {
  151. //防止行列超出Excel限制
  152. if (fileExt == ".xls")
  153. {
  154. //03版Excel最大行数是65536行,最大列数是256列
  155. if (rowNum > 65536)
  156. {
  157. return ("行数超过Excel限制!");
  158. }
  159. if (columnNum > 256)
  160. {
  161. return ("列数超过Excel限制!");
  162. }
  163. }
  164. else if (fileExt == ".xlsx")
  165. {
  166. //07版Excel最大行数是1048576行,最大列数是16384列
  167. if (rowNum > 1048576)
  168. {
  169. return ("行数超过Excel限制!");
  170. }
  171. if (columnNum > 16384)
  172. {
  173. return ("列数超过Excel限制!");
  174. }
  175. }
  176. ICell cell = dataRow.CreateCell(columnIndex);
  177. if (dgv.Rows[rowNum].Cells[columnNum].Value == null)
  178. {
  179. cell.SetCellType(CellType.Blank);
  180. }
  181. else
  182. {
  183. if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.Int32"))
  184. {
  185. cell.SetCellValue(Convert.ToInt32(dgv.Rows[rowNum].Cells[columnNum].Value));
  186. }
  187. else if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.String"))
  188. {
  189. cell.SetCellValue(dgv.Rows[rowNum].Cells[columnNum].Value.ToString());
  190. }
  191. else if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.Single"))
  192. {
  193. cell.SetCellValue(Convert.ToSingle(dgv.Rows[rowNum].Cells[columnNum].Value));
  194. }
  195. else if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.Double"))
  196. {
  197. cell.SetCellValue(Convert.ToDouble(dgv.Rows[rowNum].Cells[columnNum].Value));
  198. }
  199. else if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.Decimal"))
  200. {
  201. cell.SetCellValue(Convert.ToDouble(dgv.Rows[rowNum].Cells[columnNum].Value));
  202. }
  203. else if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.DateTime"))
  204. {
  205. cell.SetCellValue(Convert.ToDateTime(dgv.Rows[rowNum].Cells[columnNum].Value).ToString("yyyy-MM-dd"));
  206. }
  207. else if (dgv.Rows[rowNum].Cells[columnNum].ValueType.FullName.Contains("System.DBNull"))
  208. {
  209. cell.SetCellValue("");
  210. }
  211. }
  212. //设置列宽
  213. IRow currentRow;
  214. if (sheet.GetRow(rowNum) == null)
  215. {
  216. currentRow = sheet.CreateRow(rowNum);
  217. }
  218. else
  219. {
  220. currentRow = sheet.GetRow(rowNum);
  221. }
  222. if (currentRow.GetCell(columnNum) != null)
  223. {
  224. ICell currentCell = currentRow.GetCell(columnNum);
  225. int length = Encoding.Default.GetBytes(currentCell.ToString()).Length;
  226. if (columnWidth < length)
  227. {
  228. columnWidth = length + 10; //设置列宽数值
  229. }
  230. }
  231. sheet.SetColumnWidth(columnNum, columnWidth * 256);
  232. //单元格样式
  233. dataRow.GetCell(columnIndex).CellStyle = cellStyle;
  234. }
  235. }
  236. }
  237. if (!ms.CanRead) return string.Empty;
  238. //保存为Excel文件
  239. workbook.Write(ms);
  240. FileStream file = new FileStream(saveFileName, FileMode.Create);
  241. workbook.Write(file);
  242. file.Close();
  243. ms.Close();
  244. ms.Dispose();
  245. //**程序结束计时**//
  246. sw.Stop();
  247. double totalTime = sw.ElapsedMilliseconds / 1000.0;
  248. LogHelper.Info(fileName + " 导出成功\n耗时" + totalTime + "s");
  249. return string.Empty;
  250. }
  251. #endregion
  252. #region 检测文件是否被占用
  253. /// <summary>
  254. /// 判定文件是否打开
  255. /// </summary>
  256. [DllImport("kernel32.dll")]
  257. public static extern IntPtr Lopen(string lpPathName, int iReadWrite);
  258. [DllImport("kernel32.dll")]
  259. public static extern bool CloseHandle(IntPtr hObject);
  260. public const int OF_READWRITE = 2;
  261. public const int OF_SHARE_DENY_NONE = 0x40;
  262. public static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
  263. /// <summary>
  264. /// 检测文件被占用
  265. /// </summary>
  266. /// <param name="FileNames">要检测的文件路径</param>
  267. /// <returns></returns>
  268. public static bool CheckFiles(string FileNames)
  269. {
  270. if (!File.Exists(FileNames))
  271. {
  272. //文件不存在
  273. return true;
  274. }
  275. IntPtr vHandle = Lopen(FileNames, OF_READWRITE | OF_SHARE_DENY_NONE);
  276. if (vHandle == HFILE_ERROR)
  277. {
  278. //文件被占用
  279. return false;
  280. }
  281. //文件没被占用
  282. CloseHandle(vHandle);
  283. return true;
  284. }
  285. #endregion
  286. }
  287. }