ExportDgvToExcel.cs 8.6 KB

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