先贴代码后简单解释:
public static object[,] BuildTable(Stream inputStream) { object[,] table = null; using (var doc = SpreadsheetDocument.Open( inputStream,false)) { Sheet sheet = doc.WorkbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(); var worksheetPart = (WorksheetPart) doc.WorkbookPart.GetPartById(sheet.Id); var headers = worksheetPart.Worksheet.Descendants<Row>() .FirstOrDefault(x => x.RowIndex == 1); SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>(); var allRows = sheetData.Elements<Row>() .Where(x => x.RowIndex > 1 && !string.IsNullOrEmpty(x.InnerText)).ToList(); var headerCells = headers.Descendants<Cell>().ToList(); var headerCellReferences = headerCells.Select(c => Regex.Replace(c.CellReference,@"\d+",string.Empty)).ToArray(); SharedStringTablePart sstPart = doc.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First(); SharedStringTable ssTable = sstPart.SharedStringTable; WorkbookStylesPart workbookStylesPart = doc.WorkbookPart.GetPartsOfType<WorkbookStylesPart>().First(); CellFormats cellFormats = workbookStylesPart.Stylesheet.CellFormats; var headerStrings = headerCells.Select(c => ProcessCellValue(c,ssTable,cellFormats)).ToArray(); table = new object[allRows.Count + 1,headerStrings.Length]; //assign column title to the table for (int i = 0; i < headerStrings.Length; i++) { table[0,i] = headerStrings[i]; } //assign all cell values to the table for (int i = 0; i < allRows.Count; i++) { var cells = allRows[i].Elements<Cell>().Select(c => { c.CellReference = Regex.Replace(c.CellReference,string.Empty); return c; }); for (int j = 0; j < headerCells.Count; j++) { table[i + 1,j] = ProcessCellValue( cells.FirstOrDefault( c => c.CellReference == headerCellReferences[j]),cellFormats); } } } return table; } /// <summary> /// Process the valus of a cell and return a .NET value /// </summary> private static object ProcessCellValue(Cell c,SharedStringTable ssTable,CellFormats cellFormats) { if (c == null) return null; // If there is no data type,this must be a string that has been formatted as a number if (c.DataType == null) { if (c.CellValue == null) return string.Empty; if (c.StyleIndex == null) return c.CellValue.Text; CellFormat cf = cellFormats.Descendants<CellFormat>() .ElementAt<CellFormat>(Convert.ToInt32(c.StyleIndex.Value)); if (cf.NumberFormatId >= 0 && cf.NumberFormatId <= 13) // This is a number { return Convert.ToDecimal(c.CellValue.Text); } if (cf.NumberFormatId >= 14 && cf.NumberFormatId <= 22) // This is a date { return DateTime.FromOADate(Convert.ToDouble(c.CellValue.Text)); } return c.CellValue.Text; } switch (c.DataType.Value) { case CellValues.SharedString: return ssTable.ChildElements[Convert.ToInt32(c.CellValue.Text)].InnerText; case CellValues.Boolean: return c.CellValue.Text == "1"; case CellValues.Date: return DateTime.FromOADate(Convert.ToDouble(c.CellValue.Text)); case CellValues.Number: return Convert.ToDecimal(c.CellValue.Text); default: return c.CellValue != null ? c.CellValue.Text : string.Empty; } }
主要值得提的是为什么要使用EXCEL的列头(如A,B,C,D)来取数据而不是用索引。如下面代码片断:
var headerCellReferences = headerCells.Select(c => Regex.Replace(c.CellReference,string.Empty)).ToArray();
上面是把EXCEL中所有行的单元格的列头由A1,A2,B1,B2全部变成A,A,B,用于后期单元格定位。
如果当你某一列或多列EXCEL单元格是空值,那么取出来的单元格集合将不包含此列,因此集合的长度不确定, 我们不能用索引来取每一行特定单元格的值。
使用:
BuildTable(Request.Files["filename"].InputStream)
如果Exce所有列名和类所有属性列名对应,反射生成集合:
public static IEnumerable<T> BuildList<T>(object[,] table) { var list = new List<T>(); Type t = typeof(T); PropertyInfo[] props = t.GetProperties(); for (int i = 1; i < table.GetLength(0); i++) { var item = Activator.CreateInstance<T>(); for (int j = 0; j < table.GetLength(1); j++) { var title = Regex.Replace(table[0,j].ToString(),@"\s+",string.Empty); var prop = props.FirstOrDefault(p => p.Name.Equals(title,StringComparison.InvariantCultureIgnoreCase)); if (prop != null && table[i,j] != null && !string.IsNullOrEmpty(table[i,j].ToString().Trim())) { prop.SetValue(item,ConvertHelper.ChangeType(table[i,j],prop.PropertyType),null); } } list.Add(item); } return list; }
使用:
var table = ExcelHelper.BuildTable(file.InputStream); var students = ExcelHelper.BuildList<Student>(table);片断代码不严谨,请谨慎使用。