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
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|