using System;
using System.Collections;
using System.Windows.Forms;
//using Excel = Microsoft.Office.Interop.Excel;
using System;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace PTMedicalInsurance.Common
{
public class ExportToExcel
{
///
/// 将DataTable导出为CSV文件(完全替代原有的Excel导出)
///
public static string DataTabletoCSV(DataTable tmpDataTable, string strFileName)
{
// 1. 前置校验:空值和路径合法性检查
if (tmpDataTable == null || tmpDataTable.Rows.Count == 0)
{
MessageBox.Show("无导出数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return string.Empty;
}
// 校验并处理导出路径
if (!ValidateAndFixExportPath(ref strFileName))
{
return string.Empty;
}
// 确保扩展名为.csv
strFileName = EnsureCsvExtension(strFileName);
FileStream fs = null;
StreamWriter sw = null;
StringBuilder sb = new StringBuilder(65536); // 64KB缓冲区
try
{
int rowCount = tmpDataTable.Rows.Count;
int columnCount = tmpDataTable.Columns.Count;
const int batchSize = 5000; // 每批处理5000行
// 2. 创建文件流
fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None);
// 写入UTF-8 BOM,确保Excel打开不乱码
fs.WriteByte(0xEF);
fs.WriteByte(0xBB);
fs.WriteByte(0xBF);
sw = new StreamWriter(fs, Encoding.UTF8);
// 3. 写入表头
List headers = new List();
for (int i = 0; i < columnCount; i++)
{
string headerName = GetColumnNameMapping(tmpDataTable.Columns[i].ColumnName);
headers.Add(EscapeCsvValue(headerName));
}
sw.WriteLine(string.Join(",", headers));
// 4. 分批写入数据
for (int r = 0; r < rowCount; r++)
{
// 每批处理完成后写入文件
if (r > 0 && r % batchSize == 0)
{
sw.Write(sb.ToString());
sb.Clear();
sw.Flush();
Application.DoEvents(); // 防止UI卡死
}
// 构建当前行
for (int i = 0; i < columnCount; i++)
{
object cellValue = tmpDataTable.Rows[r][i];
// 格式化单元格值
if (cellValue == null || cellValue == DBNull.Value)
{
sb.Append(string.Empty);
}
else
{
string value = cellValue.ToString().Trim();
// 特殊处理:如果是数字类型但需要保留前导零(如身份证号、电话号码)
if (IsNumeric(value))
{
// 检查是否是需要保留前导零的字段
string columnName = tmpDataTable.Columns[i].ColumnName;
if (IsIdNumberField(columnName))
{
// 身份证号、电话号码等字段,强制作为文本处理
sb.Append(EscapeCsvValue(value));
}
else
{
sb.Append(value);
}
}
else
{
sb.Append(EscapeCsvValue(value));
}
}
if (i < columnCount - 1)
{
sb.Append(',');
}
}
sb.AppendLine();
}
// 5. 写入剩余数据
if (sb.Length > 0)
{
sw.Write(sb.ToString());
}
sw.Flush();
// 6. 导出成功提示
DialogResult result = MessageBox.Show(
$"CSV导出成功!\n文件路径:{strFileName}\n总行数:{rowCount}\n\n是否立即打开文件?",
"导出成功",
MessageBoxButtons.YesNo,
MessageBoxIcon.Information);
if (result == DialogResult.Yes)
{
try
{
System.Diagnostics.Process.Start(strFileName);
}
catch (Exception ex)
{
MessageBox.Show($"打开文件失败:{ex.Message}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
return strFileName;
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show($"导出失败:权限不足!请检查文件路径是否可写。\n详情:{ex.Message}",
"权限异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
return string.Empty;
}
catch (IOException ex)
{
MessageBox.Show($"导出失败:文件读写错误。\n详情:{ex.Message}",
"IO异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
return string.Empty;
}
catch (Exception ex)
{
MessageBox.Show($"导出异常:{ex.Message}\n堆栈信息:{ex.StackTrace}",
"导出异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
return string.Empty;
}
finally
{
// 7. 确保资源释放
if (sw != null)
{
try { sw.Close(); sw.Dispose(); } catch { }
}
if (fs != null)
{
try { fs.Close(); fs.Dispose(); } catch { }
}
sb.Clear();
GC.Collect();
}
}
///
/// 超大数据量导出(分页处理)- 优化版本
///
public static async Task DataTabletoCSV_BatchAsync(DataTable tmpDataTable, string strFileName, int pageSize = 10000, IProgress progress = null)
{
if (tmpDataTable == null || tmpDataTable.Rows.Count == 0)
{
MessageBox.Show("无导出数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return string.Empty;
}
if (!ValidateAndFixExportPath(ref strFileName))
{
return string.Empty;
}
strFileName = EnsureCsvExtension(strFileName);
int totalRows = tmpDataTable.Rows.Count;
int columnCount = tmpDataTable.Columns.Count;
int pageCount = (int)Math.Ceiling((double)totalRows / pageSize);
// 使用更高效的StringBuilder
StringBuilder sb = new StringBuilder(65536 * 4); // 256KB缓冲区
try
{
using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None, 81920, true)) // 80KB缓冲区,异步IO
{
// 写入UTF-8 BOM
fs.WriteByte(0xEF);
fs.WriteByte(0xBB);
fs.WriteByte(0xBF);
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8, 81920)) // 80KB缓冲区
{
// 写入表头
List headers = new List(columnCount);
for (int i = 0; i < columnCount; i++)
{
headers.Add(EscapeCsvValue(GetColumnNameMapping(tmpDataTable.Columns[i].ColumnName)));
}
await sw.WriteLineAsync(string.Join(",", headers));
// 分页写入数据
for (int page = 0; page < pageCount; page++)
{
int startRow = page * pageSize;
int endRow = Math.Min(startRow + pageSize, totalRows);
sb.Clear();
for (int r = startRow; r < endRow; r++)
{
BuildCsvRow(tmpDataTable.Rows[r], columnCount, sb);
// 每1000行输出一次,避免StringBuilder过大
if ((r - startRow + 1) % 1000 == 0 || r == endRow - 1)
{
await sw.WriteAsync(sb.ToString());
sb.Clear();
}
}
await sw.FlushAsync();
// 报告进度
progress?.Report((int)((page + 1) * 100.0 / pageCount));
// 可选:每处理完一页,让出控制权,避免UI卡死
await Task.Delay(1);
}
}
}
// 导出成功后的处理
DialogResult result = MessageBox.Show(
$"CSV导出成功!\n文件路径:{strFileName}\n总行数:{totalRows}\n\n是否立即打开文件?",
"导出成功",
MessageBoxButtons.YesNo,
MessageBoxIcon.Information);
if (result == DialogResult.Yes)
{
try
{
System.Diagnostics.Process.Start(strFileName);
}
catch (Exception ex)
{
MessageBox.Show($"打开文件失败:{ex.Message}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
return strFileName;
}
catch (Exception ex)
{
MessageBox.Show($"导出异常:{ex.Message}\n堆栈信息:{ex.StackTrace}",
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return string.Empty;
}
finally
{
// 强制垃圾回收,释放内存
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
///
/// 构建CSV行
///
private static void BuildCsvRow(DataRow row, int columnCount, StringBuilder sb)
{
for (int i = 0; i < columnCount; i++)
{
object cellValue = row[i];
if (cellValue == null || cellValue == DBNull.Value)
{
sb.Append(string.Empty);
}
else
{
string value = cellValue.ToString().Trim();
string columnName = row.Table.Columns[i].ColumnName;
// 根据字段类型处理
if (IsIdNumberField(columnName))
{
sb.Append(EscapeCsvValue(value)); // 作为文本
}
else if (IsNumeric(value))
{
sb.Append(value); // 作为数字
}
else
{
sb.Append(EscapeCsvValue(value));
}
}
if (i < columnCount - 1)
{
sb.Append(',');
}
}
sb.AppendLine();
}
///
/// 分批导出数据(同步版本,优化内存使用)
///
public static string DataTabletoCSV_BatchOptimized(DataTable tmpDataTable, string strFileName, int pageSize = 5000)
{
if (tmpDataTable == null || tmpDataTable.Rows.Count == 0)
{
MessageBox.Show("无导出数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return string.Empty;
}
if (!ValidateAndFixExportPath(ref strFileName))
{
return string.Empty;
}
strFileName = EnsureCsvExtension(strFileName);
int totalRows = tmpDataTable.Rows.Count;
int columnCount = tmpDataTable.Columns.Count;
int pageCount = (int)Math.Ceiling((double)totalRows / pageSize);
// 使用更高效的StringBuilder
StringBuilder sb = new StringBuilder(65536 * 4); // 256KB缓冲区
try
{
using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None, 81920))
{
// 写入UTF-8 BOM
fs.WriteByte(0xEF);
fs.WriteByte(0xBB);
fs.WriteByte(0xBF);
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8, 81920))
{
// 写入表头
List headers = new List(columnCount);
for (int i = 0; i < columnCount; i++)
{
headers.Add(EscapeCsvValue(GetColumnNameMapping(tmpDataTable.Columns[i].ColumnName)));
}
sw.WriteLine(string.Join(",", headers));
// 分页写入数据
for (int page = 0; page < pageCount; page++)
{
int startRow = page * pageSize;
int endRow = Math.Min(startRow + pageSize, totalRows);
sb.Clear();
for (int r = startRow; r < endRow; r++)
{
BuildCsvRow(tmpDataTable.Rows[r], columnCount, sb);
// 每1000行写入一次,避免StringBuilder过大
if ((r - startRow + 1) % 1000 == 0 || r == endRow - 1)
{
sw.Write(sb.ToString());
sb.Clear();
}
}
sw.Flush();
// 每处理完一页,检查是否有UI消息(仅在UI线程调用时)
if (Application.MessageLoop)
{
Application.DoEvents();
}
}
}
}
MessageBox.Show($"CSV导出成功!\n文件路径:{strFileName}\n总行数:{totalRows}",
"成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
return strFileName;
}
catch (Exception ex)
{
MessageBox.Show($"导出异常:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return string.Empty;
}
finally
{
GC.Collect();
}
}
///
/// 超大数据量导出(分页处理)
///
public static string DataTabletoCSV_Batch(DataTable tmpDataTable, string strFileName, int pageSize = 10000)
{
if (tmpDataTable == null || tmpDataTable.Rows.Count == 0)
{
MessageBox.Show("无导出数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return string.Empty;
}
if (!ValidateAndFixExportPath(ref strFileName))
{
return string.Empty;
}
strFileName = EnsureCsvExtension(strFileName);
int totalRows = tmpDataTable.Rows.Count;
int columnCount = tmpDataTable.Columns.Count;
int pageCount = (int)Math.Ceiling((double)totalRows / pageSize);
try
{
using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
// 写入UTF-8 BOM
fs.WriteByte(0xEF);
fs.WriteByte(0xBB);
fs.WriteByte(0xBF);
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
// 写入表头
List headers = new List();
for (int i = 0; i < columnCount; i++)
{
headers.Add(EscapeCsvValue(GetColumnNameMapping(tmpDataTable.Columns[i].ColumnName)));
}
sw.WriteLine(string.Join(",", headers));
// 分页写入数据
for (int page = 0; page < pageCount; page++)
{
int startRow = page * pageSize;
int endRow = Math.Min(startRow + pageSize, totalRows);
for (int r = startRow; r < endRow; r++)
{
List rowValues = new List(columnCount);
for (int i = 0; i < columnCount; i++)
{
object cellValue = tmpDataTable.Rows[r][i];
if (cellValue == null || cellValue == DBNull.Value)
{
rowValues.Add(string.Empty);
}
else
{
string value = cellValue.ToString().Trim();
// 根据字段类型处理
string columnName = tmpDataTable.Columns[i].ColumnName;
if (IsIdNumberField(columnName))
{
rowValues.Add(EscapeCsvValue(value)); // 作为文本
}
else if (IsNumeric(value))
{
rowValues.Add(value); // 作为数字
}
else
{
rowValues.Add(EscapeCsvValue(value));
}
}
}
sw.WriteLine(string.Join(",", rowValues));
if (r % 500 == 0)
{
Application.DoEvents();
}
}
sw.Flush();
// 可选:显示进度
int progress = (int)((page + 1) * 100.0 / pageCount);
// 可以在这里更新进度条
}
}
}
MessageBox.Show($"CSV导出成功!\n文件路径:{strFileName}\n总行数:{totalRows}",
"成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
return strFileName;
}
catch (Exception ex)
{
MessageBox.Show($"导出异常:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return string.Empty;
}
}
#region 辅助方法
///
/// 校验并修复导出路径
///
private static bool ValidateAndFixExportPath(ref string filePath)
{
try
{
// 1. 检查路径是否为空
if (string.IsNullOrWhiteSpace(filePath))
{
filePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
$"导出数据_{DateTime.Now:yyyyMMddHHmmss}.csv");
}
// 2. 检查目录是否存在
string directory = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 3. 检查文件是否被占用
if (File.Exists(filePath))
{
try
{
using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.None))
{
// 文件可写,直接返回
}
}
catch
{
DialogResult result = MessageBox.Show($"文件【{filePath}】已被占用,是否覆盖?",
"文件占用", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.No)
{
return false;
}
// 尝试删除
try { File.Delete(filePath); } catch { }
}
}
return true;
}
catch (Exception ex)
{
MessageBox.Show($"路径校验失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
///
/// 确保文件扩展名为.csv
///
private static string EnsureCsvExtension(string filePath)
{
string extension = Path.GetExtension(filePath)?.ToLower();
if (extension != ".csv")
{
return Path.ChangeExtension(filePath, ".csv");
}
return filePath;
}
///
/// 列名映射(保留原有的映射逻辑)
///
private static string GetColumnNameMapping(string originalName)
{
var columnMapping = new Dictionary
{
{ "Adm_Dr", "HIS就诊号" },
{ "MdtrtID", "医保住院号" },
{ "PatientName", "姓名" },
{ "Age", "年龄" },
{ "Gend", "性别" },
{ "PsnCertNO", "身份证号" },
{ "EmpName", "单位或地址" },
{ "PsnType", "医保类型" },
{ "AdmInDepName", "病人部门名称" },
{ "AdmBed", "床号" },
{ "MainDiagName", "入院诊断" },
{ "AttendDoctorNO", "床位医生" },
{ "ChiefPhyDocName", "门诊医生" },
{ "OpertName", "入院登记人姓名" },
{ "RegDate", "入院登记时间" },
{ "insuplcAdmdvs", "参保地区划" },
{ "InHospNo", "HIS住院号" },
{ "Address", "现住址" }
};
return columnMapping.TryGetValue(originalName, out string newName) ? newName : originalName;
}
///
/// 判断是否为身份证号等需要保留前导零的字段
///
private static bool IsIdNumberField(string columnName)
{
string lowerName = columnName.ToLower();
return lowerName.Contains("id") ||
lowerName.Contains("cert") ||
lowerName.Contains("身份证") ||
lowerName.Contains("电话") ||
lowerName.Contains("phone") ||
lowerName.Contains("code") ||
lowerName.Contains("编码");
}
///
/// 判断是否为数字
///
private static bool IsNumeric(string str)
{
return double.TryParse(str, out _);
}
///
/// 转义CSV值中的特殊字符
///
private static string EscapeCsvValue(string value)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
// 检查是否包含特殊字符
bool containsSpecialChar = value.Contains(",") ||
value.Contains("\"") ||
value.Contains("\r") ||
value.Contains("\n") ||
value.Contains("\t");
if (containsSpecialChar)
{
// 双引号转义
value = value.Replace("\"", "\"\"");
return $"\"{value}\"";
}
return value;
}
#endregion
}
}