【问题标题】:How to loop only through files that don't exist in destination using an SSIS package?如何使用 SSIS 包仅遍历目标中不存在的文件?
【发布时间】:2025-12-16 03:20:04
【问题描述】:
我在网络上有一个包含文件的文件夹,我正在将文件从一个文件夹移动到另一个文件夹。但我只想移动新文件,所以只复制目标文件夹中不存在的文件。如何?我已经有了for each 循环容器和一个文件系统任务。我正在使用变量。现在,每次执行包时,它都会将 all 文件从一个文件夹复制到下一个文件夹。是否有某种条件工具可以插入其中?我不太擅长编写脚本,所以如果这是唯一的解决方案,我可能需要你的帮助。
【问题讨论】:
标签:
file
sql-server-2008
ssis
flat
【解决方案1】:
这是一个可能的选项,您可以使用 Foreach 循环容器、脚本任务和文件系统任务来实现此目的。以下示例显示了如何做到这一点。该示例是使用 SSIS 2008 R2 创建的。
分步过程:
在路径 C:\temp\ 中创建两个名为 Source 和 Destination 的文件夹,如屏幕截图 #1 所示。
将名为 Sample_File_01.txt 的示例文件放在文件夹路径 C:\temp\Source\ 中,并将另一个文件夹 C:\temp\Destination\ 留空。仅当文件不存在时,SSIS 包才会将文件从源文件夹复制到目标文件夹。请参阅屏幕截图 #2 和 #3。
在 SSIS 包上,创建 7 个变量,如屏幕截图 #4 所示。将变量 DestinationFolder 设置为值 C:\temp\Destination\。将变量 SourceFolder 设置为值 C:\temp\Source\。将变量 FilePattern 设置为值 *.*。您可以根据需要更改这些变量的值。
选择变量SourceFilePath并按F4按钮打开Properties窗口。将属性 EvaluateAsExpression 更改为 True,并将属性 Expression 设置为值 @[User::SourceFolder] + @[User::FileName]。请参阅屏幕截图 #5。
选择变量DestinationFilePath并按F4按钮打开Properties窗口。将属性 EvaluateAsExpression 更改为 True,并将属性 Expression 设置为值 @[User::DestinationFolder] + @[User::FileName]。请参阅屏幕截图 #6。
在 SSIS 包的 C控制流 选项卡上,放置 Foreach Loop container 并配置容器的属性,如屏幕截图 #7 和 #8。确保选择Collection部分上的单选按钮Name and extension。
在 Foreach 循环容器中,放置 Script Task。双击脚本任务并单击Edit Script 按钮。将脚本任务中的 Main() 方法替换为 脚本任务代码 部分中给出的代码。此代码检查目标文件是否已存在,然后相应地填充布尔变量 DoesFileExist。
在 Foreach 循环容器中,将 File System Task 放在脚本任务下方。将脚本任务的成功绿色箭头连接到文件系统任务。如屏幕截图 #9 所示配置文件系统任务。
仅当目标路径中不存在文件时,我们才需要执行文件系统任务。因此,我们需要更改脚本任务和文件系统任务之间的连接器。右键单击绿色连接器并选择编辑,如屏幕截图 #10 所示。
如屏幕截图 #11 所示配置优先约束。这将检查变量 DoesFileExist 是否包含值 False,这意味着在目标中找不到该文件。
配置后,SSIS 包应如屏幕截图 #12 所示。
屏幕截图 #13 显示了第一个包的执行。在此执行期间,目标路径 C:\temp\Destination\ 中没有文件。执行后,文件 Sample_File_01.txt 已从C:\temp\Source\ 复制到C:\temp\Destination\。请参阅屏幕截图 #14。
屏幕截图 #15 显示了 第二 包执行。在此执行期间,没有文件被复制到目标路径C:\temp\Destination\。如您所见,File System Task 没有执行,因为优先约束失败。
希望对您有所帮助。
脚本任务代码:
C# 代码只能在 SSIS 2008 and above 中使用。
public void Main()
{
Variables varCollection = null;
Dts.VariableDispenser.LockForRead("User::DestinationFilePath");
Dts.VariableDispenser.LockForWrite("User::DoesFileExist");
Dts.VariableDispenser.GetVariables(ref varCollection);
varCollection["User::DoesFileExist"].Value = Convert.ToBoolean(System.IO.File.Exists(varCollection["User::DestinationFilePath"].Value.ToString()));
Dts.TaskResult = (int)ScriptResults.Success;
}
屏幕截图 #1:
屏幕截图 #2:
截图#3:
屏幕截图 #4:
屏幕截图 #5:
屏幕截图 #6:
截图#7:
截图#8:
屏幕截图 #9:
屏幕截图 #10:
屏幕截图 #11:
屏幕截图 #12:
屏幕截图 #13:
屏幕截图 #14:
屏幕截图 #15:
【解决方案2】:
这是一个有两个假设的潜在解决方案:
- 目标文件夹中的所有文件
被这个包裹感动了。
- 文件名是唯一的。
您可以将文件名记录步骤添加到 ETL。
在数据库中创建一个新的日志表,其中包含文件名列。在包的每个循环中,将文件名写入此表。然后,您可以将其用作简单的查找表,ETL 中的某些条件逻辑使用该查找表来检查正在处理的文件名是否与现有文件匹配。
您如何实现日志记录步骤和条件检查(可能是数据流中的条件,在脚本任务中完成等)将取决于您的包的设计,但它应该完成您正在寻找的内容。