我试图创建一个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]? “真假”
这里是你可以做到这一点的方法之一。 你可以使用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
。
希望帮助。
从调查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循环容器,看看我能在一个自定义组件复制这种逻辑。 如果我得到这个工作,我会后在评论的链接。
你能做的最好的就是使用文件规范指定一个面具,像你说的。 您可以包括它至少一些规范,比如开头“201”,2010年,2011年和2012年之后的文件,在一些其他的任务,你可以过滤掉那些你不希望处理(例如,2010)。
文章来源: How can I set an expression to the FileSpec property on Foreach File enumerator?