如何设置对Foreach文件枚举该文件规范属性的表达式?(How can I set an expr

2019-07-03 14:35发布

我试图创建一个SSIS包从包含多年价值的文件目录中处理文件。 这些文件都被命名为数字,所以为了节省处理一切,我想通过SSIS最低数量,只有列举的文件的名字(转换为数字),比我最小高。

我试着让Foreach文件枚举循环的一切,然后排除文件脚本任务,但与成百上千的文件的处理时,这是太慢是合适的。

文件规范属性用于指定文件掩码来决定你在收集想要的文件,但我不能完全看到如何用表达式来使这项工作,因为它本质上是一个字符串匹配。

如果有分量的地方,基本上说内的表达Should I Enumerate? - Yes / No Should I Enumerate? - Yes / No ,那将是完美的。 我一直在尝试用下面的表达,却找不到一个属性要应用它。

(DT_I4)REPLACE(SUBSTRING(@ [用户:: ActiveFilePath],FINDSTRING(@ [用户:: ActiveFilePath], “\”,7)+ 1,100), “” “TXT”)> @ [用户: :MinIndexId]? “真假”

Answer 1:

这里是你可以做到这一点的方法之一。 你可以使用Expression Task联合Foreach Loop Container来匹配文件名的数值。 下面是说明如何做到这一点的例子。 该示例使用SSIS 2012

这可能不是很有效,但它是这样的一种方式。

让我们假设有一个与一堆YYYYMMDD格式命名的文件的文件夹。 该文件夹中包含了自1921年以来每个月的第一天像19210101,19210201,19210301 ....所有的高达当月20121101文件。 这增加了高达1,103文件。

比方说,要求只是通过自1948年6月创建,这将意味着在SSIS包中的文件回路必须通过仅大于文件循环19480601

在SSIS包,创建以下三个参数。 这是更好地配置这些参数,因为这些值是整个环境的配置。

  • ExtensionToMatch -的该参数String的数据类型将包含该包必须通过循环扩展。 这将补充值FileSpec将Foreach循环容器上使用的变量。

  • FolderToEnumerate -这一参数String数据类型将存储,通过其中包含的文件,以循环的文件夹路径。

  • MinIndexId -的该参数Int32数据类型将包含最小数值高于该文件应匹配的模式。

创建以下四个参数,这将帮助我们遍历文件。

  • ActiveFilePath -的这个变量String作为Foreach循环容器循环遍历文件夹中的每个文件的数据类型将持有的文件名。 这个变量是在另一个变量的表达式中使用。 为了避免错误,将其设置为一个非空值,比如说1。

  • FileCount -这是一个虚拟变量Int32数据类型将被用于该样本而获得的Foreach循环容器将遍历来说明文件的数量。

  • FileSpec -的这个变量String数据类型将持有通过文件方式来循环。 这个变量的表达设定为下面提及的值。 此表达式将使用在参数指定的扩展。 如果没有扩展,它将*.*通过所有文件循环。

“*” +(@ [$包:: ExtensionToMatch] == “*”, “?”:@ [$包:: ExtensionToMatch])

  • ProcessThisFile -的该变量Boolean数据类型将评估一个特定的文件是否符合条件或没有。

配置包,如下所示。 通过所有匹配的指定的模式文件foreach循环容器将循环FileSpec变量。 上表达的任务指定的表达式将在运行时评估和将填充可变ProcessThisFile。 该变量将被上优先约束用于确定是否处理该文件或没有。

foreach循环容器内的脚本任务将递增变量计数器FileCount 1为每个成功的表达式匹配的文件。

foreach循环外的脚本任务将只显示有多少个文件都通过foreach循环容器循环。

通过使用参数,并使用该变量的文件的文件夹配置Foreach循环容器循环。

存储在变量中的文件名ActiveFilePath作为回路经过每个文件。

在表达的任务,设置表达式为以下值。 该表达式将转换的文件名,而不扩展到一个号码,然后将检查如果结果比对参数的给定数量更大MinIndexId

@ [用户:: ProcessThisFile] =(DT_BOOL)((DT_I4)(REPLACE(@ [用户:: ActiveFilePath],@ [用户:: FILESPEC], “”))> @ [$包:: MinIndexId]?1: 0)

在优先约束右键单击并将其配置为使用变量ProcessThisFile上的表达。 这告诉包处理,只有当它在表达任务设置的条件相匹配的文件。

@ [用户:: ProcessThisFile]

在第一个脚本任务,我有自己的变量User::FileCount设置为ReadWriteVariables和脚本任务中下面的C#代码。 此增量文件成功匹配的条件柜台。

public void Main()
{
    Dts.Variables["User::FileCount"].Value = Convert.ToInt32(Dts.Variables["User::FileCount"].Value) + 1;
    Dts.TaskResult = (int)ScriptResults.Success;
}

关于第二个脚本任务,我有自己的变量User::FileCount设置为ReadOnlyVariables和脚本任务中下面的C#代码。 这简单地输出已处理的文件的总数。

public void Main()
{
    MessageBox.Show(String.Format("Total files looped through: {0}", Dts.Variables["User::FileCount"].Value));
    Dts.TaskResult = (int)ScriptResults.Success;
}

当包装与MinIndexId集执行以1948061 (不含本),它输出值773

当包装与MinIndexId集执行20111201 (不包括这一点),它输出值11

希望帮助。



Answer 2:

从调查foreach循环在SSIS是如何工作的(以创建我自己来解决问题)看来,它的作品(据我可以看到反正)的方法是首先枚举该文件集,之前的任何面膜指定。 这很难说究竟发生了什么,没有看到对foreach循环的底层代码,但它似乎是做这种方式,导致性能下降超过100K的文件打交道时。

虽然@湿婆的解决方案是飞驰的详细,肯定了我最初的方法的改进,它本质上是一样的过程,除了使用表达式任务来测试文件名,而不是一个脚本任务(这似乎提供了一些改进)。

所以,我决定采取完全不同的办法,而不是使用基于文件的foreach循环枚举集合自己的脚本任务,运用我的筛选逻辑,然后遍历其余结果。 这是我做的:

在我的脚本任务,我用的是异步DirectoryInfo.EnumerateFiles方法,这对于大文件收藏推荐的方法,因为它允许数据流,而不必等待整个集合应用任何逻辑之前创建。

下面的代码:

public void Main()
{
    string sourceDir = Dts.Variables["SourceDirectory"].Value.ToString();
    int minJobId = (int)Dts.Variables["MinIndexId"].Value;

    //Enumerate file collection (using Enumerate Files to allow us to start processing immediately
    List<string> activeFiles = new List<string>();

    System.Threading.Tasks.Task listTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
    {
         DirectoryInfo dir = new DirectoryInfo(sourceDir);
         foreach (FileInfo f in dir.EnumerateFiles("*.txt"))
         {
              FileInfo file = f;
              string filePath = file.FullName;
              string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
              int jobId = Convert.ToInt32(fileName.Substring(0, fileName.IndexOf(".txt")));

              if (jobId > minJobId)
                   activeFiles.Add(filePath);
         }
    });

    //Wait here for completion
    System.Threading.Tasks.Task.WaitAll(new System.Threading.Tasks.Task[] { listTask });
    Dts.Variables["ActiveFilenames"].Value = activeFiles;
    Dts.TaskResult = (int)ScriptResults.Success;
}

所以,我列举了收集,运用我的逻辑文件被发现,并立即将文件路径进入我的列表输出。 一旦完成,我然后分配这一个SSIS对象变量命名ActiveFilenames其中我会收集我ForEach循环使用。

我配置foreach循环在foreach从变量枚举 ,现在在一个更小的集合遍历(过滤后List<string>相比,现在我只能假设是一个未经过滤的List<FileInfo>或SSIS”内置类似的东西在Foreach文件枚举

所以,我的循环中的任务可以只被专用于处理数据,因为它已经被击中循环之前进行过滤。 虽然它似乎并没有做要么我最初的包或西瓦的例子太多不同,在生产中(对于这种特殊情况下,无论如何)好像过滤收集和异步列举了使用内置的Foreach文件提供了巨大的提升枚举。

我会继续调查foreach循环容器,看看我能在一个自定义组件复制这种逻辑。 如果我得到这个工作,我会后在评论的链接。



Answer 3:

你能做的最好的就是使用文件规范指定一个面具,像你说的。 您可以包括它至少一些规范,比如开头“201”,2010年,2011年和2012年之后的文件,在一些其他的任务,你可以过滤掉那些你不希望处理(例如,2010)。



文章来源: How can I set an expression to the FileSpec property on Foreach File enumerator?