SSIS移动文件时为文件名添加日期报错求助
解决SSIS中移动并重命名CSV文件时的SUBSTRING长度错误问题
错误原因分析
你遇到的The length -1 is not valid for Function SUBSTRING错误,本质是当文件名中没有.(比如无扩展名的文件)时,FINDSTRING(@[User::ProcessedFileName],".",1)会返回0,此时FINDSTRING(...) -1就变成了-1,而SUBSTRING的长度参数要求必须是非负数,所以触发了这个报错。
方案一:修复原表达式,兼容无扩展名的情况
可以通过添加判断逻辑,确保当找不到.时,SUBSTRING的长度参数合法。修改后的表达式如下:
@[User::ArchiveFilePath] + SUBSTRING( @[User::ProcessedFileName], 1, CASE WHEN FINDSTRING(@[User::ProcessedFileName],".",1) > 0 THEN FINDSTRING(@[User::ProcessedFileName],".",1) - 1 ELSE LEN(@[User::ProcessedFileName]) END ) + "-" + (DT_STR, 2, 1252)RIGHT("0" + (DT_STR, 2, 1252)Month(@[System::StartTime]),2) + (DT_STR, 4, 1252)Year(@[System::StartTime]) + CASE WHEN FINDSTRING(@[User::ProcessedFileName],".",1) > 0 THEN SUBSTRING( @[User::ProcessedFileName], FINDSTRING(@[User::ProcessedFileName],".",1), LEN(@[User::ProcessedFileName]) ) ELSE "" END
这里做了两处关键优化:
- 用
CASE判断是否找到.,如果没找到,就取整个文件名作为前缀部分 - 月份部分添加了
RIGHT("0" + ...,2),确保单月份(比如1月)会显示为01,保持格式统一
方案二:使用TOKEN函数简化逻辑(更推荐)
SSIS的TOKEN函数可以按指定分隔符拆分字符串,比嵌套FINDSTRING+SUBSTRING更直观,也不容易出错。表达式如下:
@[User::ArchiveFilePath] + TOKEN(@[User::ProcessedFileName], ".", 1) + "-" + (DT_STR, 2, 1252)RIGHT("0" + (DT_STR, 2, 1252)Month(@[System::StartTime]),2) + (DT_STR, 4, 1252)Year(@[System::StartTime]) + IIF(TOKENCOUNT(@[User::ProcessedFileName], ".") > 1, "." + TOKEN(@[User::ProcessedFileName], ".", TOKENCOUNT(@[User::ProcessedFileName], ".")), "")
解释:
TOKEN(@[User::ProcessedFileName], ".", 1):获取.之前的文件名部分TOKENCOUNT(@[User::ProcessedFileName], "."):统计文件名中.的数量,判断是否有扩展名- 如果有扩展名,就拼接
.和最后一个分隔后的部分(避免文件名中有多个.的情况,比如file.v2.csv会保留.csv)
方案三:用脚本任务实现(最灵活)
如果你的命名规则后续可能有更复杂的变化,用C#/VB脚本任务会更灵活,也更容易调试。示例C#代码如下:
string processedFileName = Dts.Variables["User::ProcessedFileName"].Value.ToString(); string archivePath = Dts.Variables["User::ArchiveFilePath"].Value.ToString(); DateTime startTime = (DateTime)Dts.Variables["System::StartTime"].Value; // 拆分文件名和扩展名 string fileNameWithoutExt = Path.GetFileNameWithoutExtension(processedFileName); string fileExt = Path.GetExtension(processedFileName); // 拼接新文件名 string newFileName = $"{fileNameWithoutExt}-{startTime:MMyyyy}{fileExt}"; string fullArchivePath = Path.Combine(archivePath, newFileName); // 赋值给变量 Dts.Variables["User::ArchiveFilePathandName"].Value = fullArchivePath; Dts.TaskResult = (int)ScriptResults.Success;
这种方式的优势是:
- 利用.NET的
Path类,自动处理各种边界情况(比如无扩展名、多个.、路径分隔符差异) - 代码可读性更高,调试起来更方便
- 后续修改命名规则只需调整字符串拼接逻辑即可
内容的提问来源于stack exchange,提问作者ikilledbill
相关产品推荐
相关产品推荐

