在SSIS中用C#脚本获取Excel单元格IndentLevel并新建列的问题
解决SSIS中C#脚本获取Excel单元格IndentLevel的问题
嘿,我来帮你搞定这个问题!你遇到的核心问题是VBA和C#在操作Excel COM对象模型时的语法差异,还有代码里的几个小错误,以及操作顺序的逻辑问题。咱们一步步来修正:
你现有代码的几个关键错误
IndentLevel是属性不是方法:在VBA里你可以直接写Range("B16").IndentLevel,C#里这个属性同样不需要加括号(),你的代码里写了IndentLevel(),这会导致编译错误。- 工作表引用的小问题:你用
xlApp.Worksheets[1]获取工作表,更稳妥的方式是从打开的工作簿oWB里获取,避免跨工作簿的意外问题。 - 操作列的顺序逻辑错误:你先执行了
sheet.Columns["B:N"].Delete(),这会直接删掉B到N列,之后再引用sheet.Range["B13"]就会指向原来的C列(因为删除B列后,后面的列会左移),这显然和你的需求不符。
修正后的完整C#脚本(适配SSIS脚本任务)
首先确保你的SSIS脚本任务已经引用了Microsoft.Office.Interop.Excel组件(右键脚本任务的项目→添加引用→COM→找到Microsoft Excel xx.x Object Library)。
using System; using System.Windows.Forms; using Excel = Microsoft.Office.Interop.Excel; using Microsoft.SqlServer.Dts.Runtime; public void Main() { Excel.Application xlApp = null; Excel.Workbook targetWB = null; Excel.Worksheet targetSheet = null; string destFile = @"C:\Your\File\Path\YourExcelFile.xlsx"; // 替换成你的目标文件路径 try { // 初始化Excel应用 xlApp = new Excel.Application(); xlApp.Visible = true; // 调试阶段可以保留,生产环境建议设为false targetWB = xlApp.Workbooks.Open(destFile); targetSheet = (Excel.Worksheet)targetWB.Worksheets[1]; // 从当前工作簿获取第一个工作表 // 第一步:新增一列用来存储IndentLevel(比如在最前面插入新的A列) targetSheet.Columns["A:A"].Insert(Excel.XlInsertShiftDirection.xlShiftToRight); // 获取数据的最后一行(假设原来的B列是缩进级别来源列,现在插入A列后变成C列) int lastDataRow = targetSheet.Cells[targetSheet.Rows.Count, "C"].End[Excel.XlDirection.xlUp].Row; // 遍历行,把对应单元格的IndentLevel赋值到新列 for (int row = 13; row <= lastDataRow; row++) { // 来源单元格:原来的B列,现在是第3列(C列) Excel.Range sourceCell = targetSheet.Cells[row, "C"]; // 目标单元格:新增的A列 Excel.Range targetCell = targetSheet.Cells[row, "A"]; // 核心:直接访问IndentLevel属性,不需要括号 targetCell.Value = sourceCell.IndentLevel; } // 第二步:删除不需要的B:N列(现在因为插入了新A列,原来的B:N变成了C:O) targetSheet.Columns["C:O"].Delete(); // 保存更改 targetWB.Save(); MessageBox.Show("处理完成!"); Dts.TaskResult = (int)ScriptResults.Success; } catch (Exception ex) { MessageBox.Show($"处理失败:{ex.Message}\n{ex.StackTrace}"); Dts.TaskResult = (int)ScriptResults.Failure; throw; // 抛出异常让SSIS捕获详细信息 } finally { // 必须释放COM对象,否则Excel进程会在后台残留 if (targetSheet != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(targetSheet); if (targetWB != null) { targetWB.Close(); System.Runtime.InteropServices.Marshal.ReleaseComObject(targetWB); } if (xlApp != null) { xlApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp); } } } public enum ScriptResults { Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success, Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure };
关键注意事项
- COM对象释放:Excel是COM组件,必须手动释放所有引用的对象,否则会导致Excel进程在后台一直运行,占用资源。
- 列索引变化:插入或删除列后,后续列的位置会改变,一定要调整你的列引用,避免指向错误的列。
- Interop组件设置:在脚本任务的项目里,找到
Microsoft.Office.Interop.Excel的引用,把Embed Interop Types设置为False,避免版本兼容性问题。 - 生产环境设置:生产环境中记得把
xlApp.Visible = false,避免弹出Excel窗口。
内容的提问来源于stack exchange,提问作者Caio Oliveira
相关产品推荐
相关产品推荐

