.NET Framework 4.0可用EXCEL导入至DataTable
需要用到的控件为:button1 ;
openFileDialog;
dataGridView
private void button1_Click(object sender, EventArgs e){if (openFileDialog1.ShowDialog() == DialogResult.OK){try{DataTable excelData = ReadExcelToDataTable(openFileDialog1.FileName);if (excelData.Rows.Count > 0){// 输出数据dataGridView1.DataSource = excelData;}else{}}catch (Exception ex){MessageBox.Show("Excel数据导入失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);}}}public DataTable ReadExcelToDataTable(string filePath){DataTable dt = new DataTable();// 1. 打开Excel文件作为ZIP存档using (Package excelPackage = Package.Open(filePath, FileMode.Open, FileAccess.Read)){// 2. 读取共享字符串表List<string> sharedStrings = ReadSharedStrings(excelPackage);// 3. 获取活动工作表URIUri sheetUri = GetActiveWorksheetUri(excelPackage);if (sheetUri == null){// 备用方案:尝试获取第一个工作表sheetUri = GetFirstWorksheetUri(excelPackage);if (sheetUri == null)throw new Exception("Excel文件中未找到任何工作表");}// 4. 读取工作表数据PackagePart worksheetPart = excelPackage.GetPart(sheetUri);using (Stream worksheetStream = worksheetPart.GetStream())using (XmlReader reader = XmlReader.Create(worksheetStream)){bool isFirstRow = true;int maxColumns = 0;// 先确定最大列数while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.Name == "row"){using (XmlReader rowReader = reader.ReadSubtree()){int colCount = 0;while (rowReader.Read()){if (rowReader.NodeType == XmlNodeType.Element && rowReader.Name == "c"){colCount++;}}maxColumns = Math.Max(maxColumns, colCount);}}}// 重置流位置worksheetStream.Seek(0, SeekOrigin.Begin);XmlReader reader1 = XmlReader.Create(worksheetStream);// 创建足够多的列for (int i = 0; i < maxColumns; i++){dt.Columns.Add($"Column{i + 1}");}// 读取实际数据while (reader1.Read()){if (reader1.NodeType == XmlNodeType.Element && reader1.Name == "row"){DataRow row = dt.NewRow();int currentColIndex = 0;using (XmlReader rowReader = reader1.ReadSubtree()){while (rowReader.Read()){if (rowReader.NodeType == XmlNodeType.Element && rowReader.Name == "c"){string cellReference = rowReader.GetAttribute("r"); // 如"A1"string cellType = rowReader.GetAttribute("t");string cellValue = string.Empty;// 确定当前列索引currentColIndex = GetColumnIndexFromReference(cellReference);// 读取单元格值(如果有)if (rowReader.ReadToDescendant("v")){cellValue = rowReader.ReadElementContentAsString();// 处理共享字符串if (cellType == "s"){int index = int.Parse(cellValue);if (index < sharedStrings.Count)cellValue = sharedStrings[index];}}// 确保列索引在范围内if (currentColIndex >= 0 && currentColIndex < dt.Columns.Count){row[currentColIndex] = cellValue;}}}}// 填充空单元格for (int i = 0; i < dt.Columns.Count; i++){if (row[i] == null || row[i] == DBNull.Value){row[i] = string.Empty;}}dt.Rows.Add(row);}}}}return dt;}// 辅助方法:读取共享字符串表private List<string> ReadSharedStrings(Package excelPackage){List<string> sharedStrings = new List<string>();Uri sharedStringsUri = new Uri("/xl/sharedStrings.xml", UriKind.Relative);if (excelPackage.PartExists(sharedStringsUri)){PackagePart sharedStringsPart = excelPackage.GetPart(sharedStringsUri);using (Stream sharedStringsStream = sharedStringsPart.GetStream())using (XmlReader reader = XmlReader.Create(sharedStringsStream)){while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.Name == "t"){string text = reader.ReadElementContentAsString();sharedStrings.Add(text);}}}}return sharedStrings;}// 辅助方法:获取活动工作表URIprivate Uri GetActiveWorksheetUri(Package excelPackage){// 1. 读取workbook.xml获取所有工作表信息Uri workbookUri = new Uri("/xl/workbook.xml", UriKind.Relative);PackagePart workbookPart = excelPackage.GetPart(workbookUri);Dictionary<string, Tuple<string, bool>> sheets = new Dictionary<string, Tuple<string, bool>>();using (Stream workbookStream = workbookPart.GetStream())using (XmlReader reader = XmlReader.Create(workbookStream)){while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet"){string name = reader.GetAttribute("name");string sheetId = reader.GetAttribute("sheetId");string state = reader.GetAttribute("state"); // 活动状态bool isActive = (state == "visible" || string.IsNullOrEmpty(state));sheets.Add(sheetId, Tuple.Create(name, isActive));}}}// 2. 读取workbook.xml.rels获取实际路径Uri workbookRelsUri = new Uri("/xl/_rels/workbook.xml.rels", UriKind.Relative);PackagePart workbookRelsPart = excelPackage.GetPart(workbookRelsUri);Dictionary<string, string> sheetPaths = new Dictionary<string, string>();using (Stream relsStream = workbookRelsPart.GetStream())using (XmlReader reader = XmlReader.Create(relsStream)){while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.Name == "Relationship"){string id = reader.GetAttribute("Id");string target = reader.GetAttribute("Target");if (target.StartsWith("worksheets/")){sheetPaths.Add(id, target);}}}}// 3. 查找活动工作表foreach (var sheet in sheets){if (sheet.Value.Item2) // 如果是活动工作表{string sheetId = sheet.Key;if (sheetPaths.ContainsKey($"rId{sheetId}")){return new Uri("/xl/" + sheetPaths[$"rId{sheetId}"], UriKind.Relative);}}}// 如果没有明确标记的活动工作表,返回第一个可见工作表foreach (var sheet in sheets){string sheetId = sheet.Key;if (sheetPaths.ContainsKey($"rId{sheetId}")){return new Uri("/xl/" + sheetPaths[$"rId{sheetId}"], UriKind.Relative);}}return null;}// 辅助方法:从单元格引用获取列索引(如"A1" -> 0)private int GetColumnIndexFromReference(string cellReference){if (string.IsNullOrEmpty(cellReference))return -1;string columnPart = string.Empty;foreach (char c in cellReference){if (char.IsLetter(c))columnPart += c;elsebreak;}if (string.IsNullOrEmpty(columnPart))return -1;int index = 0;foreach (char c in columnPart){index = index * 26 + (char.ToUpper(c) - 'A' + 1);}return index - 1; // 转为0-based索引}// 获取第一个工作表URI(备用方案)private Uri GetFirstWorksheetUri(Package excelPackage){Uri workbookUri = new Uri("/xl/workbook.xml", UriKind.Relative);PackagePart workbookPart = excelPackage.GetPart(workbookUri);using (Stream workbookStream = workbookPart.GetStream())using (XmlReader reader = XmlReader.Create(workbookStream)){while (reader.Read()){if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet"){string sheetId = reader.GetAttribute("sheetId");return new Uri($"/xl/worksheets/sheet{sheetId}.xml", UriKind.Relative);}}}return null;}}
导入格式XLSX
上述代码可进一步改进报错信息
try{
using (FileStream stream = File.Open(openFileDialog1.FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)){catch (IOException){MessageBox.Show($"文件已被占用", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);}
界面展示: