MSExcelHelper.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. using Microsoft.Office.Interop.Excel;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Reflection;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using XYY.Core.Standard.AliYun;
  12. namespace XYY.Core.Standard.ExcelHelper.MSExcelHelper
  13. {
  14. /// <summary>
  15. /// 默认值配置
  16. /// </summary>
  17. public struct ExcelMappingConfig
  18. {
  19. /// <summary>
  20. /// 列最长宽度
  21. /// </summary>
  22. public int CoulmnMaxWidht => 50;
  23. }
  24. public class MSExcelHelper : IExcelHelper
  25. {
  26. [DllImport("User32.dll", CharSet = CharSet.Auto)]
  27. public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
  28. public static void Kill(Microsoft.Office.Interop.Excel.Application excel)
  29. {
  30. IntPtr t = new IntPtr(excel.Hwnd); //得到这个句柄,具体作用是得到这块内存入口
  31. int k = 0;
  32. GetWindowThreadProcessId(t, out k); //得到本进程唯一标志k
  33. System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k); //得到对进程k的引用
  34. p.Kill(); //关闭进程k
  35. }
  36. IAliYunPostFileSerivce _aliYunPostFileSerivce;
  37. public MSExcelHelper(IAliYunPostFileSerivce aliYunPostFileSerivce)
  38. {
  39. _aliYunPostFileSerivce = aliYunPostFileSerivce;
  40. }
  41. public MSExcelHelper()
  42. {
  43. }
  44. public string OutData<Mapping, T>(List<T> data) where Mapping : MSExcelClassMapping<T>
  45. {
  46. string filename = OutLocalData<Mapping, T>(data);
  47. string url = _aliYunPostFileSerivce.GetPublicCDN(_aliYunPostFileSerivce.PostMd5File(filename, "temp\\" + Guid.NewGuid().ToString()));
  48. //清理临时文件
  49. System.IO.File.Delete(filename);
  50. return url;
  51. }
  52. public string OutData<Mapping, T>(List<T> data, string fileName) where Mapping : MSExcelClassMapping<T>
  53. {
  54. string filename = OutLocalData<Mapping, T>(data);
  55. string url = _aliYunPostFileSerivce.GetPublicCDN(_aliYunPostFileSerivce.PostMd5File(filename, fileName));
  56. //清理临时文件
  57. System.IO.File.Delete(filename);
  58. return url;
  59. }
  60. public int GetRowCount(Worksheet worksheet)
  61. {
  62. return worksheet.Cells.Find("*", System.Reflection.Missing.Value,
  63. System.Reflection.Missing.Value, System.Reflection.Missing.Value,
  64. Microsoft.Office.Interop.Excel.XlSearchOrder.xlByRows, Microsoft.Office.Interop.Excel.XlSearchDirection.xlPrevious,
  65. false, System.Reflection.Missing.Value, System.Reflection.Missing.Value).Row;
  66. }
  67. public List<T> LoadData<Mapping, T>(string fileName) where Mapping : MSExcelClassMapping<T>
  68. {
  69. Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
  70. try
  71. {
  72. app.Visible = false; //不显示EXCEL
  73. app.DisplayAlerts = false; //不提示信息
  74. app.ScreenUpdating = false; //停止更新屏幕,加快速度
  75. Workbooks wbs = app.Workbooks; //获取工作薄
  76. _Workbook wb = wbs.Add(fileName);
  77. Microsoft.Office.Interop.Excel.Range range;
  78. List<T> list = new List<T>();
  79. var mapping = CreateT<Mapping>();
  80. List<string> sheetNames = new List<string>();
  81. foreach (Microsoft.Office.Interop.Excel.Worksheet item in wb.Sheets)
  82. {
  83. if (item.Rows.Row > 0)
  84. {
  85. sheetNames.Add(item.Name);
  86. }
  87. }
  88. var sheetsIndex = mapping.SheetIndexs(sheetNames);
  89. foreach (var si in sheetsIndex)
  90. {
  91. Worksheet sh = (Worksheet)wb.Sheets[si];
  92. range = sh.get_Range("A1", Missing.Value);
  93. var rowCount = GetRowCount(sh);
  94. var colCount = range.get_End(XlDirection.xlToRight).Column;
  95. if (rowCount > 0)
  96. {
  97. range = range.get_Resize(rowCount, colCount);
  98. object[,] value22 = (object[,])range.Value2;
  99. ///获取Map与列序号的映射关系
  100. Dictionary<int, int> keyValuePairs = new Dictionary<int, int>();
  101. for (int i = 0; i < mapping.Items.Count; i++)
  102. {
  103. for (int j = 0; j < colCount; j++)
  104. {
  105. if (mapping.Items[i].ColumnName == value22[1, j + 1].ToString())
  106. {
  107. keyValuePairs.Add(i, j + 1);
  108. continue;
  109. }
  110. }
  111. }
  112. for (int iRow = 1; iRow < rowCount; iRow++)
  113. {
  114. var item = CreateT<T>();
  115. for (int iCol = 0; iCol < mapping.Items.Count; iCol++)
  116. {
  117. try
  118. {
  119. if (keyValuePairs.ContainsKey(iCol))
  120. {
  121. var value = value22[iRow + 1, keyValuePairs[iCol]];
  122. if (value != null)
  123. {
  124. var c = mapping.Items[iCol].PropertyInfo;
  125. if (c.PropertyType == typeof(int))
  126. {
  127. c.SetValue(item, Convert.ToInt32(Convert.ToDecimal(value.ToString())));
  128. }
  129. else if (c.PropertyType == typeof(DateTime) || c.PropertyType == typeof(DateTime?))
  130. {
  131. c.SetValue(item, DateTime.FromOADate((double)value));
  132. }
  133. else if (c.PropertyType == typeof(decimal))
  134. {
  135. c.SetValue(item, Convert.ToDecimal(value.ToString()));
  136. }
  137. else if (c.PropertyType == typeof(string))
  138. {
  139. c.SetValue(item, value.ToString());
  140. }
  141. else
  142. {
  143. c.SetValue(item, value);
  144. }
  145. }
  146. }
  147. }
  148. catch (Exception ex)
  149. {
  150. Console.WriteLine(mapping.Items[iCol].PropertyInfo.Name + ex.Message);
  151. }
  152. }
  153. list.Add(item);
  154. }
  155. }
  156. }
  157. wb.Close();
  158. return list;
  159. }
  160. catch (Exception ex)
  161. {
  162. throw ex;
  163. }
  164. finally
  165. {
  166. app.Quit();
  167. }
  168. }
  169. public List<T> LoadDataByUrl<Mapping, T>(string url) where Mapping : MSExcelClassMapping<T>
  170. {
  171. var client = new System.Net.WebClient();
  172. var data = client.DownloadData(url);
  173. return LoadDataByByte<Mapping, T>(data);
  174. }
  175. public List<T> LoadDataByByte<Mapping, T>(byte[] data) where Mapping : MSExcelClassMapping<T>
  176. {
  177. string file = getTempFilePath();
  178. System.IO.File.WriteAllBytes(file, data);
  179. var result = LoadData<Mapping, T>(file);
  180. System.IO.File.Delete(file);
  181. return result;
  182. }
  183. public List<T> LoadDataAsStream<Mapping, T>(Stream stream) where Mapping : MSExcelClassMapping<T>
  184. {
  185. byte[] data = new byte[stream.Length];
  186. stream.Read(data, 0, data.Length);
  187. return LoadDataByByte<Mapping, T>(data);
  188. }
  189. public string getTempFilePath()
  190. {
  191. string basePath = System.IO.Path.Combine(System.AppContext.BaseDirectory, "temp");
  192. if (!System.IO.Directory.Exists(basePath))
  193. System.IO.Directory.CreateDirectory(basePath);
  194. return System.IO.Path.Combine(basePath, Guid.NewGuid().ToString() + ".xlsx");
  195. }
  196. private Mapping CreateT<Mapping>()
  197. {
  198. var type = typeof(Mapping);
  199. var ass = type.Assembly;
  200. Mapping mapping = (Mapping)ass.CreateInstance(type.FullName);
  201. return mapping;
  202. }
  203. public byte[] OutDataAsByte<Mapping, T>(List<T> data) where Mapping : MSExcelClassMapping<T>
  204. {
  205. string file = OutLocalData<Mapping, T>(data);
  206. byte[] bytes = System.IO.File.ReadAllBytes(file);
  207. System.IO.File.Delete(file);
  208. return bytes;
  209. }
  210. public byte[] OutDataAsByte<T>(List<T> data, List<MSExcelClassMapping<T>> list)
  211. {
  212. string file = OutLocalData<T>(data, list);
  213. byte[] bytes = System.IO.File.ReadAllBytes(file);
  214. System.IO.File.Delete(file);
  215. return bytes;
  216. }
  217. public byte[] OutDataAsByte<T, Mapping>(List<T> data, Mapping mapping) where Mapping : MSExcelClassMapping<T>
  218. {
  219. string file = OutLocalData<T, Mapping>(data, mapping);
  220. byte[] bytes = System.IO.File.ReadAllBytes(file);
  221. System.IO.File.Delete(file);
  222. return bytes;
  223. }
  224. public byte[] OutLocalTableDataByte(System.Data.DataTable data)
  225. {
  226. string file = OutLocalTableData(data);
  227. byte[] bytes = System.IO.File.ReadAllBytes(file);
  228. System.IO.File.Delete(file);
  229. return bytes;
  230. }
  231. public string OutLocalTableData(System.Data.DataTable data)
  232. {
  233. Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
  234. try
  235. {
  236. string filename = getTempFilePath();
  237. //System.IO.File.Create(filename);
  238. app.Visible = false; //不显示EXCEL
  239. app.DisplayAlerts = false; //不提示信息
  240. app.ScreenUpdating = false; //停止更新屏幕,加快速度
  241. Workbooks wbs = app.Workbooks; //获取工作薄
  242. _Workbook wb = wbs.Add(Missing.Value);
  243. Microsoft.Office.Interop.Excel.Worksheet Sheet = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets[1];
  244. OutLocalTableData(data, Sheet);
  245. app.Columns.AutoFit();
  246. wb.SaveCopyAs(filename);
  247. wb.Close(); //关闭工作薄
  248. //wb._SaveAs(filename); //保存
  249. return filename;
  250. }
  251. catch (Exception ex)
  252. {
  253. throw new Exception(ex.Message + " ");
  254. }
  255. finally
  256. {
  257. app.Quit(); //关闭EXCEL
  258. }
  259. }
  260. public void OutLocalTableData(System.Data.DataTable data, Microsoft.Office.Interop.Excel.Worksheet Sheet, string Start = "A1",
  261. System.Drawing.Color? _color = null, bool hasHeader = true)
  262. {
  263. Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
  264. //string filename = getTempFilePath();
  265. ////System.IO.File.Create(filename);
  266. //app.Visible = false; //不显示EXCEL
  267. //app.DisplayAlerts = false; //不提示信息
  268. //app.ScreenUpdating = false; //停止更新屏幕,加快速度
  269. //Workbooks wbs = app.Workbooks; //获取工作薄
  270. //_Workbook wb = wbs.Add(Missing.Value);
  271. System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"([A-Z]?)(\d+)");
  272. //Microsoft.Office.Interop.Excel.Worksheet Sheet = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets[1];
  273. //Sheet.Activate();
  274. //Sheet.Application.ActiveWindow.SplitRow = 1;
  275. //Sheet.Application.ActiveWindow.FreezePanes = true;
  276. int startQty = 1;
  277. if (regex.IsMatch(Start))
  278. {
  279. startQty = (int.Parse(regex.Match(Start).Groups[2].Value)) + 1;
  280. }
  281. else
  282. {
  283. Start = "A1";
  284. }
  285. int colCount, rowCount;
  286. colCount = data.Columns.Count;
  287. rowCount = data.Rows.Count;
  288. //写入标题行
  289. Microsoft.Office.Interop.Excel.Range range;
  290. if (hasHeader)
  291. {
  292. range = Sheet.get_Range(Start, Missing.Value);
  293. range = range.get_Resize(1, colCount);
  294. if (_color == null)
  295. range.Interior.Color = System.Drawing.Color.FromArgb(204, 255, 255);
  296. else
  297. range.Interior.Color = _color;
  298. range.Font.Bold = true;
  299. range.HorizontalAlignment = XlHAlign.xlHAlignLeft;
  300. range.VerticalAlignment = XlVAlign.xlVAlignCenter;
  301. range.Borders.LineStyle = XlLineStyle.xlContinuous;
  302. range.RowHeight = 30;
  303. object[,] headerData = new object[1, colCount];
  304. for (int iCol = 0; iCol < colCount; iCol++)
  305. {
  306. headerData[0, iCol] = data.Columns[iCol].ColumnName;
  307. //var column= Sheet.Columns[iCol] as
  308. string ColumnFormattext = ExcelFormattextHelper.GetColumnFormattext(data.Columns[iCol].DataType);
  309. if (!string.IsNullOrEmpty(ColumnFormattext))
  310. {
  311. var r2 = Sheet.Range[Sheet.Cells[startQty, iCol + 1], Sheet.Cells[data.Rows.Count + startQty, iCol + 1]];
  312. r2.NumberFormat = ColumnFormattext;
  313. }
  314. }
  315. range.set_Value(Missing.Value, headerData);
  316. }
  317. if (rowCount > 0)
  318. {
  319. if (regex.IsMatch(Start))
  320. {
  321. Start = regex.Match(Start).Groups[1].Value + (int.Parse(regex.Match(Start).Groups[2].Value) + 1);
  322. }
  323. else
  324. {
  325. Start = "A2";
  326. }
  327. range = Sheet.get_Range(Start, Missing.Value);
  328. range = range.get_Resize(rowCount, colCount);
  329. range.Borders.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous;
  330. range.RowHeight = 20;
  331. object[,] cellData = new object[rowCount, colCount];
  332. for (int iRow = 0; iRow < rowCount; iRow++)
  333. {
  334. for (int iCol = 0; iCol < colCount; iCol++)
  335. {
  336. cellData[iRow, iCol] = data.Rows[iRow][iCol];
  337. }
  338. }
  339. range.set_Value(Missing.Value, cellData);
  340. //设置单元格格式
  341. }
  342. }
  343. public void SetSheet<T, Mapping>(List<T> data, MSExcelClassMapping<T> mapping, Microsoft.Office.Interop.Excel.Worksheet Sheet, List<int> repeat = null) where Mapping : MSExcelClassMapping<T>
  344. {
  345. int colCount, rowCount;
  346. colCount = mapping.Items.Count;
  347. rowCount = data.Count;
  348. //写入标题行
  349. Microsoft.Office.Interop.Excel.Range range;
  350. range = Sheet.get_Range("A1", Missing.Value);
  351. range = range.get_Resize(1, colCount);
  352. range.Interior.Color = System.Drawing.Color.FromArgb(191, 191, 191);
  353. range.Font.Bold = true;
  354. range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignLeft;
  355. range.VerticalAlignment = Microsoft.Office.Interop.Excel.XlVAlign.xlVAlignCenter;
  356. range.Borders.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous;
  357. range.RowHeight = 30;
  358. object[,] headerData = new object[1, colCount];
  359. for (int iCol = 0; iCol < colCount; iCol++)
  360. {
  361. if (!string.IsNullOrEmpty(mapping.Items[iCol].ColumnName))
  362. {
  363. headerData[0, iCol] = mapping.Items[iCol].ColumnName;
  364. }
  365. else
  366. {
  367. headerData[0, iCol] = mapping.Items[iCol].PropertyInfo.Name;
  368. }
  369. if (!string.IsNullOrEmpty(mapping.Items[iCol].ColumnAnnotation))
  370. {
  371. //批注
  372. var r = Sheet.Range[Sheet.Cells[1, iCol + 1], Sheet.Cells[1, iCol + 1]];
  373. if (r.Comment != null)
  374. {
  375. r.Comment.Delete();
  376. }
  377. r.AddComment(mapping.Items[iCol].ColumnAnnotation);
  378. }
  379. //var column= Sheet.Columns[iCol] as
  380. if (!string.IsNullOrEmpty(mapping.Items[iCol].ColumnFormattext))
  381. {
  382. var r2 = Sheet.Range[Sheet.Cells[2, iCol + 1], Sheet.Cells[data.Count + 1, iCol + 1]];
  383. r2.NumberFormat = mapping.Items[iCol].ColumnFormattext;
  384. }
  385. }
  386. range.set_Value(Missing.Value, headerData);
  387. decimal sum = 0;
  388. int sumIndex = mapping.RemarkIndex();
  389. if (rowCount > 0)
  390. {
  391. range = Sheet.get_Range("A2", Missing.Value);
  392. range = range.get_Resize(rowCount, colCount);
  393. range.Borders.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous;
  394. range.RowHeight = 20;
  395. object[,] cellData = new object[rowCount, colCount];
  396. for (int iRow = 0; iRow < rowCount; iRow++)
  397. {
  398. for (int iCol = 0; iCol < colCount; iCol++)
  399. {
  400. var item = data[iRow];
  401. cellData[iRow, iCol] = mapping.Items[iCol].PropertyInfo.GetValue(item, null);
  402. }
  403. if (sumIndex > 0)
  404. {
  405. var item = data[iRow];
  406. sum += (decimal)mapping.Items[sumIndex + 1].PropertyInfo.GetValue(item, null);
  407. }
  408. }
  409. range.set_Value(Missing.Value, cellData);
  410. //设置单元格格式
  411. if (repeat != null)
  412. {
  413. foreach (var i in repeat)
  414. {
  415. var ranges = (Microsoft.Office.Interop.Excel.Range)Sheet.Rows[2+i, Missing.Value];
  416. ranges.Interior.Color = System.Drawing.Color.FromArgb(255, 0, 0);
  417. }
  418. }
  419. if (sumIndex > 0)
  420. {
  421. //汇总
  422. int rows = data.Count + 1;
  423. var rangeS = Sheet.get_Range("A" + (rows + 1), Missing.Value);
  424. rangeS = rangeS.get_Resize(1, colCount);
  425. rangeS.Borders.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous;
  426. rangeS.RowHeight = 20;
  427. object[,] sumData = new object[1, colCount];
  428. sumData[0, sumIndex] = "合计";
  429. sumData[0, sumIndex + 1] = sum;
  430. rangeS.set_Value(Missing.Value, sumData);
  431. }
  432. }
  433. }
  434. public string OutLocalData<T>(List<T> data, List<MSExcelClassMapping<T>> mapping)
  435. {
  436. string filename = getTempFilePath();
  437. Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
  438. try
  439. {
  440. //System.IO.File.Create(filename);
  441. app.Visible = false; //不显示EXCEL
  442. app.DisplayAlerts = false; //不提示信息
  443. app.ScreenUpdating = false; //停止更新屏幕,加快速度
  444. app.DefaultSaveFormat = XlFileFormat.xlWorkbookDefault;
  445. Workbooks wbs = app.Workbooks; //获取工作薄
  446. _Workbook wb = wbs.Add(Missing.Value);
  447. for (int i = 1; i <= mapping.Count; i++)
  448. {
  449. Microsoft.Office.Interop.Excel.Worksheet Sheet;
  450. if (i > 1)
  451. {
  452. Sheet = (Worksheet)wb.Sheets.Add(Type.Missing, wb.ActiveSheet, 1, XlSheetType.xlWorksheet);
  453. }
  454. else
  455. {
  456. Sheet = (Worksheet)wb.Sheets[i];
  457. }
  458. SetSheet<T, MSExcelClassMapping<T>>(data, mapping[i - 1], Sheet);
  459. }
  460. //Sheet.Activate();
  461. //Sheet.Application.ActiveWindow.SplitRow = 1;
  462. //Sheet.Application.ActiveWindow.FreezePanes = true;
  463. app.Columns.AutoFit();
  464. wb.SaveCopyAs(filename);
  465. wb.Close(); //关闭工作薄
  466. //wb._SaveAs(filename); //保存
  467. return filename;
  468. }
  469. catch (Exception ex)
  470. {
  471. throw new Exception(ex.Message + " " + " filename" + filename + " " + ex.StackTrace);
  472. }
  473. finally
  474. {
  475. app.Quit(); //关闭EXCEL
  476. }
  477. }
  478. public string OutLocalData<T, Mapping>(List<T> data, Mapping mapping) where Mapping : MSExcelClassMapping<T>
  479. {
  480. return OutLocalData(data, new List<MSExcelClassMapping<T>> { mapping });
  481. }
  482. /// <summary>
  483. /// 导出数据并返回本地链接
  484. /// </summary>
  485. /// <typeparam name="Mapping"></typeparam>
  486. /// <param name="data"></param>
  487. /// <param name="Sheet"></param>
  488. /// <returns></returns>
  489. public string OutLocalData<Mapping, T>(List<T> data) where Mapping : MSExcelClassMapping<T>
  490. {
  491. var mapping = CreateT<Mapping>();
  492. return OutLocalData(data, mapping);
  493. }
  494. }
  495. }