C#操作Excel
/// <summary>
/// Excel操作輔助類(無需VBA引用)
/// </summary>
public class ExcelHelper
{
/// <summary>
/// Excel 版本
/// </summary>
public enum ExcelType
{
Excel2003, Excel2007
}
/// <summary>
/// IMEX 三種模式。
/// IMEX是用來告訴驅動程式使用Excel檔案的模式,其值有0、1、2三種,分別代表匯出、匯入、混合模式。
/// </summary>
public enum IMEXType
{
ExportMode = 0, ImportMode = 1, LinkedMode = 2
}
#region 獲取Excel連線字串
/// <summary>
/// 返回Excel 連線字串 [IMEX=1]
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="header">是否把第一行作為列名</param>
/// <param name="eType">Excel 版本 </param>
/// <returns></returns>
public static string GetExcelConnectstring(string excelPath, bool header, ExcelType eType)
{
return GetExcelConnectstring(excelPath, header, eType, IMEXType.ImportMode);
}
/// <summary>
/// 返回Excel 連線字串
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="header">是否把第一行作為列名</param>
/// <param name="eType">Excel 版本 </param>
/// <param name="imex">IMEX模式</param>
/// <returns></returns>
public static string GetExcelConnectstring(string excelPath, bool header, ExcelType eType, IMEXType imex)
{
if (!FileUtil.IsExistFile(excelPath))
throw new FileNotFoundException("Excel路徑不存在!");
string connectstring = string.Empty;
string hdr = "NO";
if (header)
hdr = "YES";
if (eType == ExcelType.Excel2003)
connectstring = "Provider=Microsoft.Jet.OleDb.4.0; data source=" + excelPath + ";Extended Properties='Excel 8.0; HDR=" + hdr + "; IMEX=" + imex.GetHashCode() + "'";
else
connectstring = "Provider=Microsoft.ACE.OLEDB.12.0; data source=" + excelPath + ";Extended Properties='Excel 12.0 Xml; HDR=" + hdr + "; IMEX=" + imex.GetHashCode() + "'";
return connectstring;
}
#endregion
#region 獲取Excel工作表名
/// <summary>
/// 返回Excel工作表名
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="eType">Excel 版本 </param>
/// <returns></returns>
public static List<string> GetExcelTablesName(string excelPath, ExcelType eType)
{
string connectstring = GetExcelConnectstring(excelPath, true, eType);
return GetExcelTablesName(connectstring);
}
/// <summary>
/// 返回Excel工作表名
/// </summary>
/// <param name="connectstring">excel連線字串</param>
/// <returns></returns>
public static List<string> GetExcelTablesName(string connectstring)
{
using (OleDbConnection conn = new OleDbConnection(connectstring))
{
return GetExcelTablesName(conn);
}
}
/// <summary>
/// 返回Excel工作表名
/// </summary>
/// <param name="connection">excel連線</param>
/// <returns></returns>
public static List<string> GetExcelTablesName(OleDbConnection connection)
{
List<string> list = new List<string>();
if (connection.State == ConnectionState.Closed)
connection.Open();
DataTable dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt != null && dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
list.Add(ConvertHelper.ConvertTo<string>(dt.Rows[i][2]));
}
}
return list;
}
/// <summary>
/// 返回Excel第一個工作表表名
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="eType">Excel 版本 </param>
/// <returns></returns>
public static string GetExcelFirstTableName(string excelPath, ExcelType eType)
{
string connectstring = GetExcelConnectstring(excelPath, true, eType);
return GetExcelFirstTableName(connectstring);
}
/// <summary>
/// 返回Excel第一個工作表表名
/// </summary>
/// <param name="connectstring">excel連線字串</param>
/// <returns></returns>
public static string GetExcelFirstTableName(string connectstring)
{
using (OleDbConnection conn = new OleDbConnection(connectstring))
{
return GetExcelFirstTableName(conn);
}
}
/// <summary>
/// 返回Excel第一個工作表表名
/// </summary>
/// <param name="connection">excel連線</param>
/// <returns></returns>
public static string GetExcelFirstTableName(OleDbConnection connection)
{
string tableName = string.Empty;
if (connection.State == ConnectionState.Closed)
connection.Open();
DataTable dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt != null && dt.Rows.Count > 0)
{
tableName = ConvertHelper.ConvertTo<string>(dt.Rows[0][2]);
}
return tableName;
}
/// <summary>
/// 獲取Excel檔案中指定工作表的列
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="table">名稱 excel table 例如:Sheet1$</param>
/// <returns></returns>
public static List<string> GetColumnsList(string excelPath, ExcelType eType, string table)
{
List<string> list = new List<string>();
DataTable tableColumns = null;
string connectstring = GetExcelConnectstring(excelPath, true, eType);
using (OleDbConnection conn = new OleDbConnection(connectstring))
{
conn.Open();
tableColumns = GetReaderSchema(table, conn);
}
foreach (DataRow dr in tableColumns.Rows)
{
string columnName = dr["ColumnName"].ToString();
string datatype = ((OleDbType)dr["ProviderType"]).ToString();//對應資料庫型別
string netType = dr["DataType"].ToString();//對應的.NET型別,如System.String
list.Add(columnName);
}
return list;
}
private static DataTable GetReaderSchema(string tableName, OleDbConnection connection)
{
DataTable schemaTable = null;
IDbCommand cmd = new OleDbCommand();
cmd.CommandText = string.Format("select * from [{0}]", tableName);
cmd.Connection = connection;
using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
{
schemaTable = reader.GetSchemaTable();
}
return schemaTable;
}
#endregion
#region EXCEL匯入DataSet
/// <summary>
/// EXCEL匯入DataSet
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="table">名稱 excel table 例如:Sheet1$ </param>
/// <param name="header">是否把第一行作為列名</param>
/// <param name="eType">Excel 版本 </param>
/// <returns>返回Excel相應工作表中的資料 DataSet [table不存在時返回空的DataSet]</returns>
public static DataSet ExcelToDataSet(string excelPath, string table, bool header, ExcelType eType)
{
string connectstring = GetExcelConnectstring(excelPath, header, eType);
return ExcelToDataSet(connectstring, table);
}
/// <summary>
/// 判斷工作表名是否存在
/// </summary>
/// <param name="connection">excel連線</param>
/// <param name="table">名稱 excel table 例如:Sheet1$</param>
/// <returns></returns>
private static bool isExistExcelTableName(OleDbConnection connection, string table)
{
List<string> list = GetExcelTablesName(connection);
foreach (string tName in list)
{
if (tName.ToLower() == table.ToLower())
return true;
}
return false;
}
/// <summary>
/// EXCEL匯入DataSet
/// </summary>
/// <param name="connectstring">excel連線字串</param>
/// <param name="table">名稱 excel table 例如:Sheet1$ </param>
/// <returns>返回Excel相應工作表中的資料 DataSet [table不存在時返回空的DataSet]</returns>
public static DataSet ExcelToDataSet(string connectstring, string table)
{
using (OleDbConnection conn = new OleDbConnection(connectstring))
{
DataSet ds = new DataSet();
//判斷該工作表在Excel中是否存在
if (isExistExcelTableName(conn, table))
{
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [" + table + "]", conn);
adapter.Fill(ds, table);
}
return ds;
}
}
/// <summary>
/// EXCEL所有工作表匯入DataSet
/// </summary>
/// <param name="excelPath">Excel檔案 絕對路徑</param>
/// <param name="header">是否把第一行作為列名</param>
/// <param name="eType">Excel 版本 </param>
/// <returns>返回Excel第一個工作表中的資料 DataSet </returns>
public static DataSet ExcelToDataSet(string excelPath, bool header, ExcelType eType)
{
string connectstring = GetExcelConnectstring(excelPath, header, eType);
return ExcelToDataSet(connectstring);
}
/// <summary>
/// EXCEL所有工作表匯入DataSet
/// </summary>
/// <param name="connectstring">excel連線字串</param>
/// <returns>返回Excel第一個工作表中的資料 DataSet </returns>
public static DataSet ExcelToDataSet(string connectstring)
{
using (OleDbConnection conn = new OleDbConnection(connectstring))
{
DataSet ds = new DataSet();
List<string> tableNames = GetExcelTablesName(conn);
foreach (string tableName in tableNames)
{
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [" + tableName + "]", conn);
adapter.Fill(ds, tableName);
}
return ds;
}
}
#endregion
/// <summary>
/// 把一個數據集中的資料匯出到Excel檔案中(XML格式操作)
/// </summary>
/// <param name="source">DataSet資料</param>
/// <param name="fileName">儲存的Excel檔名</param>
public static void DataSetToExcel(DataSet source, string fileName)
{
#region Excel格式內容
var excelDoc = new StreamWriter(fileName);
const string startExcelXML = "<xml version>\r\n<Workbook " +
"xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\r\n" +
" xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n " +
"xmlns:x=\"urn:schemas- microsoft-com:office:" +
"excel\"\r\n xmlns:ss=\"urn:schemas-microsoft-com:" +
"office:spreadsheet\">\r\n <Styles>\r\n " +
"<Style ss:ID=\"Default\" ss:Name=\"Normal\">\r\n " +
"<Alignment ss:Vertical=\"Bottom\"/>\r\n <Borders/>" +
"\r\n <Font/>\r\n <Interior/>\r\n <NumberFormat/>" +
"\r\n <Protection/>\r\n </Style>\r\n " +
"<Style ss:ID=\"BoldColumn\">\r\n <Font " +
"x:Family=\"Swiss\" ss:Bold=\"1\"/>\r\n </Style>\r\n " +
"<Style ss:ID=\"StringLiteral\">\r\n <NumberFormat" +
" ss:Format=\"@\"/>\r\n </Style>\r\n <Style " +
"ss:ID=\"Decimal\">\r\n <NumberFormat " +
"ss:Format=\"#,##0.###\"/>\r\n </Style>\r\n " +
"<Style ss:ID=\"Integer\">\r\n <NumberFormat " +
"ss:Format=\"0\"/>\r\n </Style>\r\n <Style " +
"ss:ID=\"DateLiteral\">\r\n <NumberFormat " +
"ss:Format=\"yyyy-mm-dd;@\"/>\r\n </Style>\r\n " +
"</Styles>\r\n ";
const string endExcelXML = "</Workbook>";
#endregion
int sheetCount = 1;
excelDoc.Write(startExcelXML);
for (int i = 0; i < source.Tables.Count; i++)
{
int rowCount = 0;
DataTable dt = source.Tables[i];
excelDoc.Write("<Worksheet ss:Name=\"Sheet" + sheetCount + "\">");
excelDoc.Write("<Table>");
excelDoc.Write("<Row>");
for (int x = 0; x < dt.Columns.Count; x++)
{
excelDoc.Write("<Cell ss:StyleID=\"BoldColumn\"><Data ss:Type=\"String\">");
excelDoc.Write(source.Tables[0].Columns[x].ColumnName);
excelDoc.Write("</Data></Cell>");
}
excelDoc.Write("</Row>");
foreach (DataRow x in dt.Rows)
{
rowCount++;
//if the number of rows is > 64000 create a new page to continue output
if (rowCount == 64000)
{
rowCount = 0;
sheetCount++;
excelDoc.Write("</Table>");
excelDoc.Write(" </Worksheet>");
excelDoc.Write("<Worksheet ss:Name=\"Sheet" + sheetCount + "\">");
excelDoc.Write("<Table>");
}
excelDoc.Write("<Row>"); //ID=" + rowCount + "
for (int y = 0; y < source.Tables[0].Columns.Count; y++)
{
Type rowType = x[y].GetType();
#region 根據不同資料型別生成內容
switch (rowType.ToString())
{
case "System.String":
string XMLstring = x[y].ToString();
XMLstring = XMLstring.Trim();
XMLstring = XMLstring.Replace("&", "&");
XMLstring = XMLstring.Replace(">", ">");
XMLstring = XMLstring.Replace("<", "<");
excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" +
"<Data ss:Type=\"String\">");
excelDoc.Write(XMLstring);
excelDoc.Write("</Data></Cell>");
break;
case "System.DateTime":
//Excel has a specific Date Format of YYYY-MM-DD followed by
//the letter 'T' then hh:mm:sss.lll Example 2005-01-31T24:01:21.000
//The Following Code puts the date stored in XMLDate
//to the format above
var XMLDate = (DateTime)x[y];
string XMLDatetoString = XMLDate.Year +
"-" +
(XMLDate.Month < 10
? "0" +
XMLDate.Month
: XMLDate.Month.ToString()) +
"-" +
(XMLDate.Day < 10
? "0" +
XMLDate.Day
: XMLDate.Day.ToString()) +
"T" +
(XMLDate.Hour < 10
? "0" +
XMLDate.Hour
: XMLDate.Hour.ToString()) +
":" +
(XMLDate.Minute < 10
? "0" +
XMLDate.Minute
: XMLDate.Minute.ToString()) +
":" +
(XMLDate.Second < 10
? "0" +
XMLDate.Second
: XMLDate.Second.ToString()) +
".000";
excelDoc.Write("<Cell ss:StyleID=\"DateLiteral\">" +
"<Data ss:Type=\"DateTime\">");
excelDoc.Write(XMLDatetoString);
excelDoc.Write("</Data></Cell>");
break;
case "System.Boolean":
excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" +
"<Data ss:Type=\"String\">");
excelDoc.Write(x[y].ToString());
excelDoc.Write("</Data></Cell>");
break;
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.Byte":
excelDoc.Write("<Cell ss:StyleID=\"Integer\">" +
"<Data ss:Type=\"Number\">");
excelDoc.Write(x[y].ToString());
excelDoc.Write("</Data></Cell>");
break;
case "System.Decimal":
case "System.Double":
excelDoc.Write("<Cell ss:StyleID=\"Decimal\">" +
"<Data ss:Type=\"Number\">");
excelDoc.Write(x[y].ToString());
excelDoc.Write("</Data></Cell>");
break;
case "System.DBNull":
excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" +
"<Data ss:Type=\"String\">");
excelDoc.Write("");
excelDoc.Write("</Data></Cell>");
break;
default:
throw (new Exception(rowType.ToString() + " not handled."));
}
#endregion
}
excelDoc.Write("</Row>");
}
excelDoc.Write("</Table>");
excelDoc.Write(" </Worksheet>");
sheetCount++;
}
excelDoc.Write(endExcelXML);
excelDoc.Close();
}
/// <summary>
/// 將DataTable匯出為Excel(OleDb 方式操作)
/// </summary>
/// <param name="dataTable">表</param>
/// <param name="fileName">匯出預設檔名</param>
public static void DataSetToExcel(DataTable dataTable, string fileName)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "xls files (*.xls)|*.xls";
saveFileDialog.FileName = fileName;
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
fileName = saveFileDialog.FileName;
if (File.Exists(fileName))
{
try
{
File.Delete(fileName);
}
catch
{
MessageBox.Show("該檔案正在使用中,關閉檔案或重新命名匯出檔案再試!");
return;
}
}
OleDbConnection oleDbConn = new OleDbConnection();
OleDbCommand oleDbCmd = new OleDbCommand();
string sSql = "";
try
{
oleDbConn.ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=" + fileName + @";Extended ProPerties=""Excel 8.0;HDR=Yes;""";
oleDbConn.Open();
oleDbCmd.CommandType = CommandType.Text;
oleDbCmd.Connection = oleDbConn;
sSql = "CREATE TABLE sheet1 (";
for (int i = 0; i < dataTable.Columns.Count; i++)
{
// 欄位名稱出現關鍵字會導致錯誤。
if (i < dataTable.Columns.Count - 1)
sSql += "[" + dataTable.Columns[i].Caption + "] TEXT(100) ,";
else
sSql += "[" + dataTable.Columns[i].Caption + "] TEXT(200) )";
}
oleDbCmd.CommandText = sSql;
oleDbCmd.ExecuteNonQuery();
for (int j = 0; j < dataTable.Rows.Count; j++)
{
sSql = "INSERT INTO sheet1 VALUES('";
for (int i = 0; i < dataTable.Columns.Count; i++)
{
if (i < dataTable.Columns.Count - 1)
sSql += dataTable.Rows[j][i].ToString() + " ','";
else
sSql += dataTable.Rows[j][i].ToString() + " ')";
}
oleDbCmd.CommandText = sSql;
oleDbCmd.ExecuteNonQuery();
}
MessageBox.Show("匯出EXCEL成功");
}
catch (Exception ex)
{
MessageBox.Show("匯出EXCEL失敗:" + ex.Message);
}
finally
{
oleDbCmd.Dispose();
oleDbConn.Close();
oleDbConn.Dispose();
}
}
}
}