tijian_jichuang/Code/xiaoy.Excel/ExcelFile.cs
2025-02-20 11:54:48 +08:00

536 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ================================================================================
// File: ExcelFile.cs
// Desc: Excel操作类。
// 主要功能是用于Excel数据的导入导出。
//
// Called by:
//
// Auth: 汪洋
// Date: 2010年8月20日
// ================================================================================
// Change History
// ================================================================================
// Date: Author: Description:
// -------- -------- -------------------
//
// ================================================================================
// Copyright (C) 2010-2012
// ================================================================================
using System;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
namespace xiaoy.Excel
{
/// <summary>
/// Excel文件操作类。
/// </summary>
public class ExcelFile
{
#region
//excel版本默认为98-2003版Excel。
string m_version=string.Empty;
//连接串中的HDR属性用于标识第一行是列名。默认是。
string m_hdr = string.Empty;
//excel文件路径
string m_filePath = string.Empty;
DataTable m_dataSource = null;
//缓存静态变量
static NameValueCollection m_excelVersion = null;
static NameValueCollection m_excelTypeMap = null;
static int m_maxSheelSize = 0;
#endregion
#region
/// <summary>
/// 静态构造函数
/// </summary>
static ExcelFile()
{
m_excelVersion = AppConfig.GetConfig(AppConfigKey.ExcelVersionKey);
m_excelTypeMap = AppConfig.GetConfig(AppConfigKey.ExcelTypeKey);
m_maxSheelSize = int.Parse(AppConfig.AppSettings[AppConfigKey.MaxSheelSize]);
////将m_excelVersion值中的'替换成"
//foreach (string key in m_excelVersion.Keys)
//{
// m_excelVersion[key] = m_excelVersion[key].Replace("'","\"");
//}
}
/// <summary>
/// 无参构造函数
/// </summary>
public ExcelFile():this(null)
{ }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="excelVersion">Excel文档版本使用ExcelVersion类型。</param>
public ExcelFile(string excelVersion)
{
//设置默认值
m_version = ExcelVersion.Excel8;
m_hdr = HDRType.Yes;
//覆盖默认值
if (!string.IsNullOrEmpty(excelVersion))
{
m_version = excelVersion;
}
}
#endregion
#region
/// <summary>
/// 获取或设置Excel文档版本号。
/// 为ExcelVersion类型的值。
/// </summary>
public string Version
{
get
{
return m_version;
}
set
{
m_version = value;
}
}
/// <summary>
/// 获取或设置HDR类型。
/// </summary>
public string HDR
{
get
{
return HDR;
}
set
{
HDR = value;
}
}
/// <summary>
/// 获取或设置Excel文件路径。
/// </summary>
public string FilePath
{
get
{
return m_filePath;
}
set
{
m_filePath = value;
}
}
/// <summary>
/// 获取或设置数据源。
/// </summary>
public DataTable DataSource
{
get
{
return m_dataSource;
}
set
{
m_dataSource = value;
}
}
#endregion
#region
/// <summary>
/// 导入DataSource到Excel中
/// </summary>
public void Import()
{
SetData(DataSource, FilePath, Version, HDR);
}
/// <summary>
/// 获取Excel中的数据
/// </summary>
/// <param name="bMerge">多表数据是否合并</param>
/// <returns>DataTable集合</returns>
public DataTable[] GetData(bool bMerge)
{
return GetData(FilePath, Version, HDR, bMerge);
}
#endregion
#region
/// <summary>
/// 写数据到Excel。
/// </summary>
/// <param name="dtSource">数据源</param>
/// <param name="filePath">Excel导出路径</param>
/// <param name="excelVersion">excel版本为ExcelVersion类型</param>
/// <param name="pHDR">第一行是否标题为HDRType类型</param>
public static void SetData(DataTable dtSource, string filePath, string excelVersion, string pHDR)
{
//数据源为空
if (dtSource == null)
{
throw new Exception("无数据可导");
}
//保存路径为空
if(string.IsNullOrEmpty(filePath))
{
throw new Exception("未设置Excel保存路径");
}
//删除文件
if (File.Exists(filePath))
{
File.Delete(filePath);
}
string connectionString = string.Format(m_excelVersion[excelVersion],
filePath,pHDR);
// 连接Excel
using(OleDbConnection Connection = new OleDbConnection(connectionString))
{
Connection.Open();
//导入数据
using(OleDbCommand command = new OleDbCommand())
{
command.Connection = Connection;
//构建列 格式如Name VarCharCreateDate Date
string colList = CreateExcelColums(dtSource);
//构建插入SQL语句
//格式如 "INSERT INTO TABLE [tablename](col1,col2,col3) VALUES(@col1,@col2,@col3)";
StringBuilder sbColumNames = new StringBuilder();
StringBuilder sbColumValues = new StringBuilder();
int c = 0;
foreach (DataColumn dc in dtSource.Columns)
{
sbColumNames.AppendFormat(",[{0}]", dc.ColumnName);
sbColumValues.AppendFormat(",@{0}", "c_"+c.ToString());
c++;
}
//去掉多余的逗号
sbColumNames.Remove(0, 1);
sbColumValues.Remove(0, 1);
//当数据量超过每页最大数据量时,自动分页
int totalRows = dtSource.Rows.Count;//总数据量
int pageIndex = 0;
//开始插入数据 do...while循环是为了处理分页逻辑
do
{
//计算此轮插入的数据量
int insertRows = m_maxSheelSize - 1;
//如果总数据量没有达到容量
if (totalRows < insertRows)
{
insertRows = totalRows;
}
string tableName = dtSource.TableName + pageIndex;
if (pageIndex == 0)
{
tableName = "Sheet1";
}
//创建表框架
StringBuilder sbCom = new StringBuilder();
sbCom.Append("CREATE TABLE [");
sbCom.Append(tableName);
sbCom.Append("](");
sbCom.Append(colList);
sbCom.Append(")");
command.CommandText = sbCom.ToString();
try
{
command.ExecuteNonQuery();
}
catch(Exception ex)
{
//如果使用Create语句创建失败则直接创建Excel文件
CreateExcelFile(filePath, excelVersion, command.CommandText);
}
//插入数据
sbCom = new StringBuilder();
sbCom.AppendFormat("INSERT INTO [{0}]({1}) VALUES({2})",
tableName, sbColumNames.ToString(), sbColumValues.ToString());
int startIndex = pageIndex * (m_maxSheelSize-1);
int endIndex = pageIndex * (m_maxSheelSize-1) + insertRows;
for (int i = startIndex; i < endIndex; i++)
{
DataRow drData = dtSource.Rows[i];
OleDbParameterCollection dbParam = command.Parameters;
dbParam.Clear();
c = 0;
foreach (DataColumn dc in dtSource.Columns)
{
dbParam.Add(new OleDbParameter("@" + "c_"+c.ToString(), GetOleDbTypeByDataColumn(dc)));
dbParam["@" + "c_" + c.ToString()].Value = drData[dc.ColumnName];
c++;
}
command.CommandText = sbCom.ToString();
command.ExecuteNonQuery();
}
//计算剩余数据量
totalRows = totalRows - insertRows;
pageIndex++;
}while(totalRows > 0);
}//end of using OleDbCommand
}// end of using OleDbConnection
}
/// <summary>
/// 从Excel读数据
/// </summary>
/// <param name="filePath">excel文档路径</param>
/// <param name="excelVersion">文档版本</param>
/// <param name="pHDR">第一行是否标题</param>
/// <param name="bMerge">
/// 如果有多页,是否合并数据,合并时必须保证多页的表结构一致
/// </param>
/// <returns>DataTable集</returns>
public static DataTable[] GetData(string filePath, string excelVersion, string pHDR,bool bMerge)
{
List<DataTable> dtResult = new List<DataTable>();
string connectionString = string.Format(m_excelVersion[excelVersion],
filePath,pHDR);
using (OleDbConnection con = new OleDbConnection(connectionString))
{
con.Open();
string[] sheels = GetExcelWorkSheets(filePath, excelVersion);
foreach (string sheelName in sheels)
{
try
{
DataTable dtExcel = new DataTable();
OleDbDataAdapter adapter = new OleDbDataAdapter("Select * from [" + sheelName + "$]", con);
adapter.FillSchema(dtExcel, SchemaType.Mapped);
adapter.Fill(dtExcel);
dtExcel.TableName = sheelName;
dtResult.Add(dtExcel);
}
catch
{
//容错处理:取不到时,不报错,结果集为空即可。
}
}
//如果需要合并数据,则合并到第一张表
if (bMerge)
{
for (int i = 1; i < dtResult.Count; i++)
{
//如果不为空才合并
if (dtResult[0].Columns.Count==dtResult[i].Columns.Count &&
dtResult[i].Rows.Count > 0)
{
dtResult[0].Load(dtResult[i].CreateDataReader());
}
}
}
}
return dtResult.ToArray();
}
#endregion
#region
/// <summary>
/// 返回指定文件所包含的工作簿列表;如果有WorkSheet就返回以工作簿名字命名的ArrayList否则返回空
/// </summary>
/// <param name="filePath">要获取的Excel</param>
/// <param name="excelVersion">文档版本</param>
/// <returns>如果有WorkSheet就返回以工作簿名字命名的string[],否则返回空</returns>
private static string[] GetExcelWorkSheets(string filePath, string excelVersion)
{
List<string> alTables = new List<string>();
string connectionString = string.Format(m_excelVersion[excelVersion],
filePath, "Yes");
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
connection.Open();
DataTable dt = new DataTable();
dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
throw new Exception("无法获取指定Excel的架构。");
}
foreach (DataRow dr in dt.Rows)
{
string tempName = dr["Table_Name"].ToString();
int iDolarIndex = tempName.IndexOf('$');
if (iDolarIndex > 0)
{
tempName = tempName.Substring(0, iDolarIndex);
}
//修正Excel2003中某些工作薄名称为汉字的表无法正确识别的BUG。
if (tempName[0] == '\'')
{
if (tempName[tempName.Length - 1] == '\'')
{
tempName = tempName.Substring(1, tempName.Length - 2);
}
else
{
tempName = tempName.Substring(1, tempName.Length - 1);
}
}
if (!alTables.Contains(tempName))
{
alTables.Add(tempName);
}
}
}
if (alTables.Count == 0)
{
return null;
}
return alTables.ToArray();
}
/// <summary>
/// 创建Excel文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="excelVersion">excel版本</param>
/// <param name="excelVersion">创建sheet的脚本</param>
private static void CreateExcelFile(string filePath, string excelVersion,string createSql)
{
string outputDir = Path.GetDirectoryName(filePath);
//导出路径不存在则创建
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
//导出文件不存在则创建,存在则重写
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
if (excelVersion == ExcelVersion.Excel12)
{
//创建2007Excel
fs.Write(Properties.Resources._2007, 0, Properties.Resources._2007.Length);
}
else
{
//其他默认创建2003Excel
fs.Write(Properties.Resources._2003, 0, Properties.Resources._2003.Length);
}
//插入Sheet表。
string connectionString = string.Format(m_excelVersion[excelVersion],
filePath, "Yes");
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
connection.Open();
using (OleDbCommand command = new OleDbCommand())
{
command.CommandText = createSql;
command.ExecuteNonQuery();
}
}
}
}
/// <summary>
/// 构建Excel列脚本。
/// 格式如Name VarCharCreateDate Date
/// </summary>
/// <param name="dtSource"></param>
/// <returns></returns>
private static string CreateExcelColums(DataTable dtSource)
{
//检查列数
if (dtSource.Columns.Count == 0)
{
throw new Exception("数据源列数为0");
}
//构建列
StringBuilder sbColums = new StringBuilder();
foreach (DataColumn dc in dtSource.Columns)
{
sbColums.AppendFormat(",[{0}] {1}", dc.ColumnName, GetExcelTypeByDataColumn(dc));
}
//去掉多余的逗号
sbColums.Remove(0, 1);
return sbColums.ToString();
}
/// <summary>
/// 获取DataColumn对应的Excel列类型
/// </summary>
/// <param name="dc">源数据的列</param>
/// <returns>Excel列类型名称</returns>
private static string GetExcelTypeByDataColumn(DataColumn dc)
{
foreach (string key in m_excelTypeMap.Keys)
{
if (key == dc.DataType.Name)
{
return m_excelTypeMap[dc.DataType.Name];
}
}
return m_excelTypeMap[AppConfigKey.DefaultTypeKey];
}
/// <summary>
/// 获取DataColumn对应的Excel列类型
/// </summary>
/// <param name="dc">源数据的列</param>
/// <returns>Excel列类型名称</returns>
private static OleDbType GetOleDbTypeByDataColumn(DataColumn dc)
{
switch (dc.DataType.Name)
{
case "String"://字符串
return OleDbType.VarChar;
case "Double"://数字
return OleDbType.Double;
case "Decimal"://数字
return OleDbType.Decimal;
case "DateTime"://时间
return OleDbType.Date;
default:
return OleDbType.VarChar;
}
}
#endregion
}
}