代码之家  ›  专栏  ›  技术社区  ›  thursdaysgeek

当没有可下载的文件时,如何避免SSIS FTP任务失败?

  •  18
  • thursdaysgeek  · 技术社区  · 17 年前

    我正在使用SQLServer2005,并在SSIS中创建ftp任务。

    有时会有文件通过ftp传输,有时不会。如果没有文件,我不希望任务或包失败。我已经将ftp任务的箭头改为“completion”,这样包就可以运行了。我已经将允许的错误数更改为4(因为有4个ftp任务,并且4个目录中的任何一个都可能有文件,也可能没有文件)。

    但是,当我从代理中的作业运行包时,它会将作业标记为失败。由于这将运行每15分钟,我不希望在我的工作历史上有一堆红色的x的,这将导致我们没有看到一个问题时,它真的发生了。

    如何在ftp任务中设置属性,以使找不到ftp文件不会失败?我使用的操作是“发送文件”。

    这里有更多的信息:这些文件在一个服务器上,除了ftp之外,我没有任何访问权限。而且,我不知道提前的文件名。用户可以随意调用它们。所以我不能检查具体的文件,我想,我也不能检查。除非通过使用ftp连接和基于该连接的任务。这些文件在一个远程服务器上,我想把它们复制到我的服务器上,从那个远程服务器上获取它们。

    我可以在脚本任务中shell命令级ftp。也许这就是我需要使用的,而不是ftp任务(我已经改为使用ftp命令行,带有一个从脚本任务调用的参数文件。当没有要获取的文件时,它不会出错。我想这个办法对我有用。我正在动态创建参数文件,这意味着我不需要在纯文本文件中包含连接信息,而是可以存储在配置文件中,该文件位于更安全的位置。)

    12 回复  |  直到 14 年前
        1
  •  14
  •   user756519 user756519    14 年前

    我知道你已经找到了问题的答案。这是为其他用户谁可能偶然发现这个问题。这里有一种可能的实现方法。 Script Task 可用于查找给定模式的FTP文件夹路径中存在的文件列表(例如 *.txt ). 下面的例子展示了如何做到这一点。

    逐步过程:

    1. 在SSIS包上,创建 FTP Connection 命名 文件传输协议 同时创造 5 RemotePath 包含FTP文件夹路径; LocalPath FilePattern 包含文件模式,用于查找要从FTP服务器下载的文件列表; FileName 将由 Foreach loop container / 或者 DelayValidation FTP任务的属性可以设置为 是的 .

    2. 在SSIS包上,放置 , Foreach Loop container FTP Task Foreach循环容器 如截图所示#

    3. 更换 Main() 脚本任务 代码在 脚本任务代码 与给定模式匹配的文件集合。这个例子将首先使用模式*.txt,它不会产生任何结果,然后使用模式*.xls,它将匹配FTP服务器上的几个文件。

    4. 配置 Foreach循环容器 4

    5. 配置 如截图所示# 5 6 .

    6. 显示以下情况下的示例包执行 找到模式的匹配文件 *.txt文件 .

    7. 截图# 8 显示文件夹的内容 C:\temp\ 包的执行。

    8. 截图# *.xls .

    9. 显示FTP远程路径的内容 /Practice/Directory_New .

    10. 截图# 显示文件夹的内容 C:\温度\ 之后 包的执行。

    11. 12 当提供了不正确的 远程路径

    12. 截图# 13 显示与包失败相关的错误消息。

    希望有帮助。

    脚本任务代码:

    C级# SSIS 2008 and above .

    包括 using 陈述

    public void Main()
    {
        Variables varCollection = null;
        ConnectionManager ftpManager = null;
        FtpClientConnection ftpConnection = null;
        string[] fileNames = null;
        string[] folderNames = null;
        System.Collections.ArrayList listOfFiles = null;
        string remotePath = string.Empty;
        string filePattern = string.Empty;
        Regex regexp;
        int counter;
    
        Dts.VariableDispenser.LockForWrite("User::RemotePath");
        Dts.VariableDispenser.LockForWrite("User::FilePattern");
        Dts.VariableDispenser.LockForWrite("User::ListOfFiles");
        Dts.VariableDispenser.GetVariables(ref varCollection);
    
        try
        {
            remotePath = varCollection["User::RemotePath"].Value.ToString();
            filePattern = varCollection["User::FilePattern"].Value.ToString();
    
            ftpManager = Dts.Connections["FTP"];
            ftpConnection = new FtpClientConnection(ftpManager.AcquireConnection(null));
            ftpConnection.Connect();
            ftpConnection.SetWorkingDirectory(remotePath);
            ftpConnection.GetListing(out folderNames, out fileNames);
            ftpConnection.Close();
    
            listOfFiles = new System.Collections.ArrayList();
            if (fileNames != null)
            {
                regexp = new Regex("^" + filePattern + "$");
                for (counter = 0; counter <= fileNames.GetUpperBound(0); counter++)
                {
                    if (regexp.IsMatch(fileNames[counter]))
                    {
                        listOfFiles.Add(remotePath + fileNames[counter]);
                    }
                }
            }
    
            varCollection["User::ListOfFiles"].Value = listOfFiles;
        }
        catch (Exception ex)
        {
            Dts.Events.FireError(-1, string.Empty, ex.ToString(), string.Empty, 0);
            Dts.TaskResult = (int) ScriptResults.Failure;
        }
        finally
        {
            varCollection.Unlock();
            ftpConnection = null;
            ftpManager = null;
        }
    
        Dts.TaskResult = (int)ScriptResults.Success;
    }
    

    VB语言 可用于 SSIS 2005 and above

    Imports

    Public Sub Main()
        Dim varCollection As Variables = Nothing
        Dim ftpManager As ConnectionManager = Nothing
        Dim ftpConnection As FtpClientConnection = Nothing
        Dim fileNames() As String = Nothing
        Dim folderNames() As String = Nothing
        Dim listOfFiles As Collections.ArrayList
        Dim remotePath As String = String.Empty
        Dim filePattern As String = String.Empty
        Dim regexp As Regex
        Dim counter As Integer
    
        Dts.VariableDispenser.LockForRead("User::RemotePath")
        Dts.VariableDispenser.LockForRead("User::FilePattern")
        Dts.VariableDispenser.LockForWrite("User::ListOfFiles")
        Dts.VariableDispenser.GetVariables(varCollection)
    
        Try
    
            remotePath = varCollection("User::RemotePath").Value.ToString()
            filePattern = varCollection("User::FilePattern").Value.ToString()
    
            ftpManager = Dts.Connections("FTP")
            ftpConnection = New FtpClientConnection(ftpManager.AcquireConnection(Nothing))
    
            ftpConnection.Connect()
            ftpConnection.SetWorkingDirectory(remotePath)
            ftpConnection.GetListing(folderNames, fileNames)
            ftpConnection.Close()
    
            listOfFiles = New Collections.ArrayList()
            If fileNames IsNot Nothing Then
                regexp = New Regex("^" & filePattern & "$")
                For counter = 0 To fileNames.GetUpperBound(0)
                    If regexp.IsMatch(fileNames(counter)) Then
                        listOfFiles.Add(remotePath & fileNames(counter))
                    End If
                Next counter
            End If
    
            varCollection("User::ListOfFiles").Value = listOfFiles
    
            Dts.TaskResult = ScriptResults.Success
    
        Catch ex As Exception
            Dts.Events.FireError(-1, String.Empty, ex.ToString(), String.Empty, 0)
            Dts.TaskResult = ScriptResults.Failure
        Finally
            varCollection.Unlock()
            ftpConnection = Nothing
            ftpManager = Nothing
        End Try
    
        Dts.TaskResult = ScriptResults.Success
    End Sub
    

    截图1:

    1

    2

    截图3:

    3

    截图4:

    4

    截图5:

    5

    截图6:

    6

    截图7:

    7

    截图8:

    8

    截图9:

    9

    截图#10:

    10

    截图#11:

    11

    12

    13

        2
  •  14
  •   Rich Rich    14 年前

    看看这个 link 它描述了如何优雅地处理SSIS包中的任务错误。

    希望这也能帮你解决!

        3
  •  5
  •   tribe84    10 年前

    我刚刚遇到了这个问题,在阅读了这里的一些回复之后,没有什么能真正解决我的问题,这里的解决方案在复杂性方面似乎是疯狂的。

    我的解决办法很简单:

    1. 右键单击任务-属性
    2. Set ForceExecutionResult=“成功”
        4
  •  3
  •   thursdaysgeek    14 年前

    这也许不是最好的解决方案,但这是可行的。

    我使用一个脚本任务,有一堆变量用于ftp连接信息,以及源目录和目标目录(因为,我们将更改运行此功能的服务器,并且在配置包中更改会更容易。)

    我动态创建一个文本文件,并向其中写入ftp命令:

        Dim ftpStream As StreamWriter = ftpFile.CreateText()
        ftpStream.WriteLine(ftpUser)
        ftpStream.WriteLine(ftpPassword)
        ftpStream.WriteLine("prompt off")
        ftpStream.WriteLine("binary")
        ftpStream.WriteLine("cd " & ftpDestDir)
        ftpStream.WriteLine("mput " & ftpSourceDir)
        ftpStream.WriteLine("quit 130")
        ftpStream.Close()
    

        ftpParameters = "-s:" & ftpParameterLoc & ftpParameterFile & " " & ftpServer
        proc = System.Diagnostics.Process.Start("ftp", ftpParameters)
    

    然后,在给它更多的时间让ftp进程运行之后,我删除了临时ftp文件(其中包含连接信息!)。

    如果源目录中不存在文件(变量具有\\drive\dir\*.*映射),则不存在错误。如果发生其他错误,任务仍然会失败。

    正如我指出的,我无法知道这些文件的名称,甚至根本不知道那里是否有任何文件。如果他们在那里,我想得到他们。

        5
  •  1
  •   Tom H zenazn    17 年前

    您应该能够在ActiveX脚本任务中设置一个变量,然后使用该变量来决定是否应该运行FTP任务。有一个例子 here 这适用于本地路径。希望您可以调整这个概念(或者如果可能的话,映射FTP驱动器并这样做)。

        6
  •  1
  •   Todd Hoffert    7 年前

    2) 将此代码添加到FTP任务OnError事件处理程序。

        public void Main()
        {
            // TODO: Add your code here
    
            int errorCode = (int)Dts.Variables["System::ErrorCode"].Value;
    
            if (errorCode.ToString().Equals("-1073573501"))
            {
                Dts.Variables["System::Propagate"].Value = false;
            }
            else
            {
                Dts.Variables["System::Propagate"].Value = true;
            }
    
    
            Dts.TaskResult = (int)ScriptResults.Success;
        }
    
        7
  •  0
  •   Meff    17 年前

    把它放在ForEach容器中,该容器遍历要上载的文件。没有文件,没有FTP,没有失败。

        8
  •  0
  •   Amr ElGarhy    17 年前

    为此,添加新的脚本任务,突出显示FTP任务,第二个绿色连接器将出现,将其拖到脚本任务,然后双击它。在“值”下拉列表中选择“失败”。显然,您将需要处理此脚本任务中的实际失败,以便仍然显示在作业历史记录中。

        9
  •  0
  •   Meff    17 年前

    啊哈,好吧-谢谢你的澄清。由于FTP任务无法返回文件夹列表,因此无法使用ForEach,正如我最初所说的那样-只有将X个文件上载到远程源时,ForEach才有效。

    要下载X数量的文件,可以采用两种方式,一种是完全在.Net脚本任务中完成,另一种是用.Net脚本任务中的文件名填充ArrayList,然后在ArrayList上ForEach,将文件名传递给一个变量,然后在标准FTP任务中下载该变量名。

    代码示例: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=2472491&SiteID=1

    因此,在上面,您将获得FileNames()并从中填充ArrayList,然后将ArrayList分配给Dts.Variables中的一个对象类型变量,然后使用如下代码将ForEach分配给该对象(ArrayList)变量: http://www.sqlservercentral.com/articles/SSIS/64014/

        10
  •  0
  •   Kilani    15 年前

    以下是功能页的链接: http://www.easkills.com/ssis/ftptask

        11
  •  0
  •   Chad    13 年前

    1) 在包中创建一个名为FTP\u Error的变量

    2) 单击FTP任务,然后单击“事件处理程序”选项卡

    3) 在页面中单击以创建“FTP Task/OnError”的事件处理程序-每当FTP出现问题时,此操作都会触发

    4) 从工具箱中,拖入脚本任务项,然后双击以打开它

    5) 在第一个弹出窗口中,ReadOnlyVariables-add System::ErrorCode,System::ErrorDescription

    7) 编辑脚本

    8) 在脚本中,设置FTP\u Error变量以保存上面的ReadOnlyVariables:

    Dts.Variables["FTP_Error"].Value = "ErrorCode:" + Dts.Variables["ErrorCode"].Value.ToString() + ", ErrorDescription=" + Dts.Variables["ErrorDescription"].Value.ToString();
    

    10) 点击“确定”来编写任务脚本

    12) 从FTP任务,OnError转到一个新的脚本任务,并编辑它

    13) ReadOnlyVariables:User::FTP\u之前的错误

    14) 现在,当FTP上找不到文件时,错误代码是-1073573501 (您可以在此处找到错误代码参考列表: http://msdn.microsoft.com/en-us/library/ms345164.aspx )

    15) 在你的脚本中,输入逻辑来做你想做的事情——如果你发现一个“找不到文件”的代码,那么也许你说任务成功了。如果不是,则任务失败。你的正常流量可以按你的意愿处理:

    if (Dts.Variables["FTP_Error"].Value.ToString().Contains("-1073573501"))
    {
      // file not found - not a problem
      Dts.TaskResult = (int)ScriptResults.Success;
    }
    else
    {
      // some other error - raise alarm!
      Dts.TaskResult = (int)ScriptResults.Failure;
    }
    

    从那里,你的成功/失败流将做你想做的事情。

        12
  •  0
  •   Joost    13 年前

    另一种方法是使用 FTP File Enumerator enter image description here

    推荐文章