You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
14 KiB

1 year ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using CK.SCP.Utils;
namespace ChangkeTec.Utils
{
public class EpPlusHelper
{
private DataSet _dsExcel;
private DataTable _dtExcel;
private string _excelFileName;
private List<string> _readSheetNames;
private BackgroundWorker _bgw;
private string _pasword = string.Empty;
public Action<DataTable> ReadCompleted;
readonly SaveFileDialog _sfd = new SaveFileDialog
{
Filter = "Excel 工作簿 (*.xlsx)|*.xlsx",
CheckFileExists = false,
CheckPathExists = false,
FilterIndex = 0,
RestoreDirectory = true,
CreatePrompt = false,
Title = "保存为Excel文件"
};
public EpPlusHelper()
{
_bgw = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
}
#region Read
public void ReadExcelToDt(string fileName, string password = "")
{
_excelFileName = fileName;
_pasword = password;
var excelFileExt = GetFileExt(fileName);
switch (excelFileExt)
{
case ".XLSX":
var poDv = new ProcessOperator { BackgroundWork = ReadExcelToDataTable };
poDv.BackgroundWorkerCompleted += ReadExcel_Completed;
poDv.Start();
break;
case ".XLS":
throw new Exception($"需要使用NPOI解析后缀名为{excelFileExt}的文件!");
default:
throw new Exception($"无法解析后缀名为{excelFileExt}的文件!");
}
//return _dtExcel;
}
private DataTable ReadData(ExcelWorksheet sheet)
{
var dt = new DataTable(sheet.Name);
int colStart = sheet.Dimension.Start.Column;
int colEnd = sheet.Dimension.End.Column;
int rowStart = sheet.Dimension.Start.Row;
int rowEnd = sheet.Dimension.End.Row;
for (var i = colStart; i < colEnd + 1; i++)//从1开始计数
{
var columnName = sheet.Cells[rowStart, i].Value?.ToString();
dt.Columns.Add(columnName);
}
for (var row = rowStart + 1; row < rowEnd + 1; row++)//从1开始计数,跳过第一行
{
var dr = dt.NewRow();
for (var col = colStart; col < colEnd + 1; col++)//从1开始计数
{
dr[col - 1] = sheet.Cells[row, col]?.Value?.ToString();
}
dt.Rows.Add(dr);
}
RemoveEmptyRow(dt);
return dt;
}
private void ReadExcelToDataTable()
{
_readSheetNames = new List<string>();
_dsExcel = new DataSet();
var fs = new FileStream(_excelFileName, FileMode.Open);
try
{
using (
var package = string.IsNullOrEmpty(_pasword)
? new ExcelPackage(fs)
: new ExcelPackage(fs, _pasword)
)
{
var validSheetList = GetValidSheetList(package);
if (validSheetList.Count == 0) throw new Exception("未找到有效的Excel表单");
var sheet = validSheetList[0];
_readSheetNames.Add(sheet.Name);
_dtExcel = ReadData(sheet);
}
}
finally
{
fs.Close();
fs.Dispose();
}
}
private void ReadExcel_Completed(object sender, BackgroundWorkerEventArgs e)
{
if (e.BackGroundException == null)
{
if (_readSheetNames == null || _readSheetNames.Count == 0)
{
throw new Exception("文件读失败,未找到符合的系统要求的工作表!");
}
else if (ReadCompleted != null)
{
ReadCompleted(_dtExcel);
}
}
else
{
throw new Exception("文件读取失败,请联系管理员!");
}
}
private List<ExcelWorksheet> GetValidSheetList(ExcelPackage package)
{
var list = new List<ExcelWorksheet>();
for (var i = 1; i <= package.Workbook.Worksheets.Count; i++)
{
var sheet = package.Workbook.Worksheets[i];
var tableName = sheet.Name;
if (!tableName.Equals("_xlnm#_FilterDatabase") &&
tableName.IndexOf("_", StringComparison.Ordinal) != tableName.Length - 1 &&
tableName.IndexOf("FilterDatabase", StringComparison.Ordinal) == -1)
{
list.Add(sheet);
}
}
return list;
}
private void GetFileName(string fileName)
{
_excelFileName = fileName;
}
private string GetFileExt(string fileName)
{
return Path.GetExtension(fileName)?.ToUpper();
}
#endregion
#region Write
public void WriteDsToExcel(DataSet ds, string password = "")
{
if (_sfd.ShowDialog() != DialogResult.OK) return;
var fileName = _sfd.FileName;
WriteDsToExcel(ds, fileName, password);
}
public void WriteDsToExcel(DataSet ds, string excelFileName, string password)
{
if (ds == null || ds.Tables.Count == 0)
throw new Exception("当前表单没有任何数据");
var poDv = new ProcessOperator
{
BackgroundWork = () => WriteDataSetToExcel(ds, excelFileName, password)
};
poDv.BackgroundWorkerCompleted += WriteExcel_Completed;
poDv.Start();
}
private void WriteDataSetToExcel(DataSet ds, string excelFileName, string password)
{
var newFile = GetNewFile(excelFileName);
_excelFileName = excelFileName;
using (var package = string.IsNullOrEmpty(password) ? new ExcelPackage(newFile) : new ExcelPackage(newFile, password))
{
foreach (DataTable dt in ds.Tables)
{
if (string.IsNullOrEmpty(dt?.TableName) || dt.Rows.Count == 0) continue;
EpPlusHelper.RemoveEmptyRow(dt);
var sheetName = "sheet1";
if (!string.IsNullOrEmpty(dt.TableName))
sheetName = dt.TableName;
var worksheet = package.Workbook.Worksheets.Add(sheetName);
//表头
SetTitle(dt, worksheet);
//各行数据
SetData(dt, worksheet);
//设置单元格格式
SetFormat(worksheet);
}
if (package.Workbook.Worksheets.Count <= 0) return;
if (string.IsNullOrEmpty(password))
package.Save();
else
package.Save(password);
}
}
public void WriteDtToExcel(DataTable dt, string password = "")
{
if (_sfd.ShowDialog() != DialogResult.OK) return;
var fileName = _sfd.FileName;
WriteDtToExcel(dt, fileName, password);
}
public void WriteDtToExcel(DataTable dt, string excelFileName, string password)
{
var excelFileExt = GetFileExt(excelFileName);
switch (excelFileExt)
{
case ".XLSX":
if (dt == null || dt.Rows.Count <= 0) throw new Exception("当前表单没有任何数据");
var poDv = new ProcessOperator { BackgroundWork = () => WriteDataTableToExcel(dt, excelFileName, password) };
poDv.BackgroundWorkerCompleted += WriteExcel_Completed;
poDv.Start();
break;
case ".XLS":
throw new Exception($"需要使用NPOI解析后缀名为{excelFileExt}的文件!");
default:
throw new Exception($"无法解析后缀名为{excelFileExt}的文件!");
}
}
private static FileInfo GetNewFile(string excelFileName)
{
var newFile = new FileInfo(excelFileName);
if (newFile.Exists)
{
newFile.Delete(); // ensures we create a new workbook
newFile = new FileInfo(excelFileName);
}
return newFile;
}
private void WriteDataTableToExcel(DataTable dt, string excelFileName, string password)
{
var newFile = GetNewFile(excelFileName);
_excelFileName = excelFileName;
using (var package = string.IsNullOrEmpty(password) ? new ExcelPackage(newFile) : new ExcelPackage(newFile, password))
{
var sheetName = "sheet1";
if (!string.IsNullOrEmpty(dt.TableName))
sheetName = dt.TableName;
using (var worksheet = package.Workbook.Worksheets.Add(sheetName))
{
//表头
SetTitle(dt, worksheet);
//各行数据
SetData(dt, worksheet);
//设置单元格格式
SetFormat(worksheet);
if (string.IsNullOrEmpty(password))
package.Save();
else
package.Save(password);
}
}
}
private void WriteExcel_Completed(object sender, BackgroundWorkerEventArgs e)
{
var newFile = new FileInfo(_excelFileName);
if (newFile.Exists)
Process.Start(_excelFileName);
}
private static void SetFormat(ExcelWorksheet worksheet)
{
if (worksheet.Dimension == null) return;
int colStart = worksheet.Dimension.Start.Column;
int colEnd = worksheet.Dimension.End.Column;
int rowStart = worksheet.Dimension.Start.Row;
int rowEnd = worksheet.Dimension.End.Row;
// using (var range = worksheet.Cells[1, 1, 1, dt.Columns.Count])
using (var range = worksheet.Cells[rowStart, colStart, rowStart, colEnd])
{
range.Style.Fill.PatternType = ExcelFillStyle.LightGrid;
range.Style.Fill.BackgroundColor.SetColor(Color.LightYellow);
range.Style.HorizontalAlignment = ExcelHorizontalAlignment.CenterContinuous;
}
// using (var range = worksheet.Cells[1, 1, dt.Rows.Count + 1, dt.Columns.Count])
using (var range = worksheet.Cells[rowStart, colStart, rowEnd, colEnd])
{
range.Style.Border.BorderAround(ExcelBorderStyle.Thin);
range.Style.Font.Name = "微软雅黑";
range.Style.Font.Size = 12;
range.AutoFitColumns();
}
}
private static void SetData(DataTable dt, ExcelWorksheet worksheet)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
var row = i + 2;
for (int j = 0; j < dt.Columns.Count; j++)
{
var col = j + 1;
var s = dt.Rows[i][j];
//////////////////
//格式化日期字段
var dc = dt.Columns[j];
if (dc.DataType.FullName == "System.DateTime")
{
DateTime time;
DateTime.TryParse(s.ToString(), out time);
s = time.ToString("yyyy-MM-dd HH:mm:ss");
}
//使用EPPLUS貌似不需要做这个转换了?
// if (dc.DataType.FullName == "System.String")
// {
// s = "'" + s;
// }
decimal d;
if (decimal.TryParse(s.ToString(), out d))
{
if (Math.Round(d, 5) == 0)
{
s = 0;
}
}
worksheet.Cells[row, col].Value = s;
}
}
}
private static void SetTitle(DataTable dt, ExcelWorksheet worksheet)
{
int row = 1;
for (int i = 0; i < dt.Columns.Count; i++)
{
var dc = dt.Columns[i];
row = 1;
var col = i + 1;
worksheet.Cells[row, col].Value = dc.ColumnName;
}
worksheet.View.FreezePanes(row + 1, 1); //冻结表头
}
#endregion
public static void RemoveEmptyRow(DataTable dt)
{
if (dt == null || dt.Rows.Count == 0)
return;
var isEmpty = true;
for (var idx = dt.Rows.Count - 1; idx >= 0; idx--)
{
var dr = dt.Rows[idx];
for (var i = 0; i < dt.Columns.Count; i++)
{
if (dr[i].ToString().Trim() != string.Empty)
{
isEmpty = false;
}
}
if (isEmpty)
dt.Rows.Remove(dr);
}
}
}
}