SSIS脚本任务处理目录时触发调用目标运行时异常求助
SSIS脚本任务遍历目录写入SQL报错问题解决方案
报错核心原因
- 逻辑顺序错误:代码先执行
Directory.GetFiles(DirPath, "*"),后判断目录是否存在。如果目标目录不存在,第一步就会抛出异常,根本走不到后面的判断分支,且该行代码无实际使用,属于冗余逻辑。 - SQL拼接语法错误:直接拼接文件路径、名称到SQL语句中,如果文件名/路径包含单引号(例如
员工'报销表.xlsx),会直接导致SQL语法错误,触发执行异常。 - 权限不足:遍历第5个目录时,可能遇到当前SSIS运行账号无读取权限的子文件夹/文件,触发权限异常直接中断任务。
- 路径过长:Windows默认限制路径长度不超过260字符,如果目录下有超长路径的文件/文件夹,.NET Framework默认会抛出路径无效异常。
- 逻辑缺陷:现有代码仅遍历子目录下的文件,根目录下的文件不会被写入SQL表。
修复后代码
public void Main() { SqlConnection myADONETConnection = null; try { // 初始化数据库连接 myADONETConnection = (SqlConnection)(Dts.Connections["DBConn"].AcquireConnection(Dts.Transaction) as SqlConnection); SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = myADONETConnection; // 预定义参数化SQL,避免拼接语法错误和注入风险 sqlCmd.CommandText = "Insert into dbo.FileInformation_6 Values(@FullName, @FileName, @LastAccessTime, @CreationTime, @FileSize)"; string DirPath = Dts.Variables["User::VarDirectoryPath"].Value.ToString(); // 先判断目录是否存在,再执行后续操作 if (!Directory.Exists(DirPath)) { MessageBox.Show("目录不存在:" + DirPath); Dts.TaskResult = (int)ScriptResults.Failure; return; } // 处理根目录下的文件 string[] rootFiles = Directory.GetFiles(DirPath); foreach (string rootFile in rootFiles) { ProcessFile(rootFile, sqlCmd); } // 遍历所有子目录 string[] folders = Directory.GetDirectories(DirPath, "*", SearchOption.AllDirectories); foreach (string foldername in folders) { try { string[] fnames = Directory.GetFiles(foldername); foreach (string filename in fnames) { ProcessFile(filename, sqlCmd); } } catch (Exception ex) { // 跳过无法访问的文件夹,可根据需要改为记录日志 MessageBox.Show($"跳过无法处理的文件夹 {foldername},错误:{ex.Message}"); continue; } } Dts.TaskResult = (int)ScriptResults.Success; } catch (Exception globalEx) { // 捕获全局异常,方便定位问题 MessageBox.Show($"任务运行错误:{globalEx.Message}\n堆栈:{globalEx.StackTrace}"); Dts.TaskResult = (int)ScriptResults.Failure; } finally { // 释放数据库连接 if (myADONETConnection != null) { Dts.Connections["DBConn"].ReleaseConnection(myADONETConnection); } } } // 抽离文件处理公共方法,避免重复代码 private void ProcessFile(string filePath, SqlCommand sqlCmd) { try { FileInfo file = new FileInfo(filePath); // 清空上一次的参数值 sqlCmd.Parameters.Clear(); sqlCmd.Parameters.AddWithValue("@FullName", file.FullName); sqlCmd.Parameters.AddWithValue("@FileName", file.Name); sqlCmd.Parameters.AddWithValue("@LastAccessTime", file.LastAccessTime); sqlCmd.Parameters.AddWithValue("@CreationTime", file.CreationTime); sqlCmd.Parameters.AddWithValue("@FileSize", file.Length / 1024); sqlCmd.ExecuteNonQuery(); } catch (Exception ex) { // 跳过无法处理的文件,可根据需要改为记录日志 MessageBox.Show($"跳过无法处理的文件 {filePath},错误:{ex.Message}"); } }
额外优化建议
- 生产环境建议将
MessageBox.Show替换为SSIS日志记录,避免弹窗阻塞任务运行 - 如果需要支持超长路径,可在项目属性中开启.NET 4.6.2以上版本的长路径支持,同时修改Windows组策略关闭长路径限制
- 可以批量插入数据代替单条插入,提升大量文件时的执行效率
内容的提问来源于stack exchange,提问作者Dhipthee Pujar
相关产品推荐
相关产品推荐

