C# 使用 SSIS 检查文件夹中的几个特定文件

C# Using SSIS to check for several specific files in a folder

我有一个包含 10 个左右文本文件的列表,我需要确保它们在特定时间在 SSIS 中存在于特定文件夹中。如果这些文件存在,我将启动一个包,如果不存在,我将通过电子邮件发送给客户。我在检查单个文件时没有问题,但我无法遍历所有文件以找到我需要的特定文件。

一个例子是我需要文件 A.txt b.txt e.txt 和 z.txt 并且在目录中你有 a.txt 到 y.txt但没有 z.txt。我希望这是有道理的。如果有人可以帮助我,我将不胜感激! SQL 2008 R2 顺便说一句和 VS 2008。

从数据库的角度来看,这将是从应该存在的 table 个文件到实际存在的 table 个文件的左连接(显示不匹配)。问题是这不是数据库上下文。

您可以将 10 个文件的名称存储在一个 table 中,然后将存在的所有文件的名称导入到一个 "temporary" table 中,从而将其合并。这将使比较变得容易。

遍历文件夹中的所有文件永远不会成为一个优雅的解决方案,因为你必须检查 10 个文件,在 AND 的基础上(它们必须都存在,否则你做其他事情)。你必须在你的 C# 代码中有 10 个标志,当相应的文件出现在循环中时设置每个标志,并在最后检查它们是否全部为 TRUE。这不好玩。

最好只遍历 10 个文件名(这意味着您必须将它们放入某种可循环结构中,例如 table)。然后 C# 代码可以对每个文件执行 System.IO.File.Exists,如果找不到任何文件,请重置您在开始时设置的 AllFilesAreThere 标志。

有很多方法可以解决这个问题,但如果您对 C# 感兴趣,我会看一下类似 Enumerable.Intersect 的方法。

Intersection,正如我们都从集合论中回忆的那样,是同时存在于 A 和 B 中的组。在您的情况下,您的第一个集合将是 "expected" 集合(a.txt、b.txt、e.txt 和 z.txt)。根据需要定义该列表。您可以从 table 中提取它,对列表进行硬编码,随便什么。

var expected = new List<string>() {
    @"C:\ssisdata\so\input\so_36362799_a.txt", 
    @"C:\ssisdata\so\input\so_36362799_b.txt" };

第二组将是"actual"。由于我们在 .NET 领域,我会查看 System.IO.Directory.GetFiles 方法从我们的文件夹中提取所有 .txt 文件。

var actual = System.IO.Directory.GetFiles(@"C:\ssisdata\so\input", "so*.txt");

此时我们有两个集合,物理上实现为 List<string> 但任何实现 IEnumerable 的东西都应该足够了。如果我生成两个列表的交集,我会受到挫折。如果您需要知道哪些文件不在交叉点中,那么您应该捕获结果集。不过我们不在乎,我们只想知道 "do we have all the files we need"

expected.Intersect(actual)

由于我们不关心可能丢失了哪些文件,我们可以简单地计算我们预期的元素数量并将其与交集进行比较。如果计数相同,那么我们应该拥有所需的所有文件。

expected.Count() == expected.Intersect(actual).Count()

因为这是 Windows,我们需要担心区分大小写的问题。在 Unix 世界中,一个目录可以有 foo.txt、Foo.txt、foo.TXT 等,只要区分大小写的文件名是唯一的。 Windows 没有那种担心。 But,确定交集 的字符串比较将 区分大小写,因此如果可能的话,一个人而不是一个程序将生成这些文件,您可能希望强制文件名 upper/lower 大小写与您的预期设置一致。

综合起来,您会得到这样的脚本任务。很多改进的机会。我们可以传入源文件夹、我们的文件列表、文件掩码,然后如果我们没有找到我们期望找到的所有文件应该发生什么——现在它使脚本任务失败。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using Microsoft.SqlServer.Dts.Runtime;

namespace ST_6fabd2d80a6340399c540f8fdeaebf97
{
    /// <summary>
    /// Whosebug 36362799
    /// </summary>
    [Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
    public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
    {

        /// <summary>
        /// Determine if all the files in our expected set match the actual set
        /// </summary>
        public void Main()
        {
            var expected = new List<string>() { @"C:\ssisdata\so\input\so_36362799_a.txt", @"C:\ssisdata\so\input\so_36362799_b.txt" };
            var actual = System.IO.Directory.GetFiles(@"C:\ssisdata\so\input", "so*.txt");
            bool pokemon = expected.Count() == expected.Intersect(actual).Count();

            if (pokemon)
            {
                Dts.TaskResult = (int)ScriptResults.Success;
            }
            else
            {
                Dts.TaskResult = (int)ScriptResults.Failure;
            }
        }

        enum ScriptResults
        {
            Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
            Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
        };
    }
}

由于这是用 SQL Server 2008 标记的,因此默认脚本任务将针对 .NET 框架 2.0。上面的代码将不起作用,因为 intersect 调用将需要 System.Linq 命名空间。这是一个简单的补救措施,在脚本任务中,右键单击项目 (ST_#########) 并转到属性菜单。