在最近的一個項目中,有大量的數據源來至Excel,轉成JSON供前台使用。Excel數據是人工錄入的,難免會有錯誤,所以中間會有邏輯檢查。在C#中讀取Excel的方式有很多,網上一搜一大堆,這里我也貼出一個ExcelHelper,提供根據Excel文件獲取所有Sheet名稱和獲取Sheet內容兩個方法。使用的時候記得注冊AccessDatabaseEngine,該驅動有64位、32位兩個版本,請根據自己的環境選擇正確的版本。
using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.Linq; namespace Math.Library.Helper { public class ExcelHelper { public static DataTable GetExcelContent(String filePath, string sheetName) { if (sheetName == "_xlnm#_FilterDatabase") return null; DataSet dateSet = new DataSet(); String connectionString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR=NO;IMEX=1;'", filePath); String commandString = string.Format("SELECT * FROM [{0}$]", sheetName); using (OleDbConnection connection = new OleDbConnection(connectionString)) { connection.Open(); using (OleDbCommand command = new OleDbCommand(commandString, connection)) { OleDbCommand objCmd = new OleDbCommand(commandString, connection); OleDbDataAdapter myData = new OleDbDataAdapter(commandString, connection); myData.Fill(dateSet, sheetName); DataTable table = dateSet.Tables[sheetName]; for (int i = 0; i < table.Rows[0].ItemArray.Length; i++) { var cloumnName = table.Rows[0].ItemArray[i].ToString(); if (!string.IsNullOrEmpty(cloumnName)) table.Columns[i].ColumnName = cloumnName; } table.Rows.RemoveAt(0); return table; } } } public static List<string> GetExcelSheetNames(string filePath) { OleDbConnection connection = null; System.Data.DataTable dt = null; try { String connectionString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR=YES;IMEX=1;'", filePath); connection = new OleDbConnection(connectionString); connection.Open(); dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null); if (dt == null) { return new List<string>(); } String[] excelSheets = new String[dt.Rows.Count]; int i = 0; foreach (DataRow row in dt.Rows) { excelSheets[i] = row["TABLE_NAME"].ToString().Split('$')[0]; i++; } return excelSheets.Distinct().ToList(); } catch (Exception ex) { LogHelper.Logger.Error(ex); return new List<string>(); } finally { if (connection != null) { connection.Close(); connection.Dispose(); } if (dt != null) { dt.Dispose(); } } } } }
假如我的Excel數據如下,有班級和學生兩張表(實際上有上百個Sheet,這里只做演示之用)。
當然我們不可能為每一個Sheet都對應做一個數據Model,不僅繁瑣,還很容易出錯。這時我想到了Newtonsoft.Json,Newtonsoft.Json是.NET下開源的JSON格式序列化和反序列化的類庫。其中Newtonsoft.Json.Linq提供了對LINQ支持,支持動態對象、數組的序列化。
將整個Excel轉換為一個JSON文件,每一個Sheet Name作為Key,Content就是Value,Value以數組形式存在,最終得到數據格式如下:
對應的代碼如下,JArray和JObject是Newtonsoft.Json中的對象,支持動態屬性和方法,表名和列名就是這樣插入JSON中的。
class Program { static void ExcelToJson() { List<string> tableNames = ExcelHelper.GetExcelSheetNames("test.xlsx"); var json = new JObject(); tableNames.ForEach(tableName => { var table = new JArray() as dynamic; DataTable dataTable = ExcelHelper.GetExcelContent("test.xlsx", tableName); foreach (DataRow dataRow in dataTable.Rows) { dynamic row = new JObject(); foreach (DataColumn column in dataTable.Columns) { row.Add(column.ColumnName, dataRow[column.ColumnName].ToString()); } table.Add(row); } json.Add(tableName, table); }); Console.WriteLine(json.ToString()); Console.WriteLine(json.ToString(Formatting.None)); } static void Main(string[] args) { ExcelToJson(); } }
當然,為了減少前后端傳輸數據的流量,可以使用ToString(Formatting.None),這樣生成出來的數據就沒有格式了。