我正在使用SQL Server 2005,并在SSIS中创建ftp任务。
有时会有ftp文件,有时不会。如果没有文件,我不希望任务和包失败。我已经将箭头从ftp任务更改为下一个“完成”,因此包运行完毕。我已将允许的错误数量更改为4(因为有4个ftp任务,并且4个目录中的任何一个可能有也可能没有文件)。
但是,当我从代理中的作业运行包时,它将作业标记为失败。由于这将每15分钟运行一次,我不希望在我的工作历史中出现一堆红色x,这将导致我们在确实发生时不会发现问题。
如何在ftp任务中设置属性,以便不向ftp查找文件不是故障?我正在使用的操作是“发送文件”。
以下是一些更多信息:文件位于服务器上,除了ftp之外我没有任何访问权限。而且,我提前不知道文件名。用户可以随意调用它们。所以我不能检查具体的文件,我认为,我可以检查。除了通过使用基于该连接的ftp连接和任务。这些文件位于远程服务器上,我想将它们复制到我的服务器上,以便从远程服务器上获取它们。
我可以在脚本任务中填充命令级别ftp。也许这就是我需要使用而不是ftp任务。 (我已经更改为使用ftp命令行,带有一个参数文件,从脚本任务调用。当没有文件可以获取时,它没有错误。我认为这个解决方案对我有用。我正在创建动态参数文件,这意味着我不需要在纯文本文件中有连接信息,而是可以存储在我的配置文件中,该文件位于更安全的位置。)
答案 0 :(得分:14)
选中此link,其中介绍了如何在SSIS包中正常处理任务错误。
我有几乎相同的问题但是,检索文件。我希望在FTP服务器上找不到文件时包不会失败。上面的链接会阻止错误冒泡并导致程序包失败;你会想到FailPackageOnError = false应该做的事情吗? :-S
希望这也能为你解决它!
答案 1 :(得分:14)
我知道您找到了问题的答案。这适用于可能偶然发现此问题的其他用户。这是实现这一目标的一种可能方式。 Script Task
可用于查找给定模式的FTP文件夹路径中存在的文件列表(例如*.txt
)。下面的例子说明了如何做到这一点。
分步流程:
在SSIS包上,创建名为 FTP 的FTP Connection
,并创建 5 变量,如屏幕截图# 1 。变量RemotePath
包含FTP文件夹路径; LocalPath
包含文件将被下载到的文件夹; FilePattern
包含用于查找要从FTP服务器下载的文件列表的文件模式; FileName
将填充Foreach loop container
,但为了避免FTP任务设计时错误,可以使用 / 填充它,或者FTP任务上的DelayValidation
属性可以填充设置为 True 。
在SSIS包中,在Script Task
中放置Foreach Loop container
,FTP Task
和Foreach Loop container
,如屏幕截图# 2 所示
将Main()
内的Script Task
方法替换为脚本任务代码部分下的代码。脚本任务将使用与给定模式匹配的文件集合填充变量 ListOfFiles 。这个例子将首先使用模式* .txt,它不会产生任何结果,然后是模式* .xls,它将匹配FTP服务器上的几个文件。
配置Foreach Loop container
,如屏幕截图# 3 和# 4 所示。此任务将循环遍历变量** ListOfFiles *。如果没有文件,循环容器内的FTP任务将不会执行。如果有文件,循环容器内的FTP任务将执行FTP服务器上找到的文件数的任务。
配置FTP Task
,如屏幕截图# 5 和# 6 所示。
屏幕截图# 7 显示了为模式*.txt
找到无匹配文件时的示例包执行情况。
屏幕截图# 8 显示执行包之前文件夹C:\temp\
的内容。
屏幕截图# 9 显示为模式*.xls
找到匹配文件时的示例包执行。
屏幕截图# 10 显示FTP远程路径/Practice/Directory_New
的内容。
屏幕截图# 11 显示执行
C:\temp\
的内容。
屏幕截图# 12 显示提供错误远程路径时的程序包失败。
屏幕截图# 13 显示与程序包失败相关的错误消息。
希望有所帮助。
脚本任务代码:
可以在SSIS 2008 and above
中使用的C#代码。
使用System.Text.RegularExpressions包含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;
}
可以在 SSIS 2005 and above
中使用的VB 代码。
包含Imports
声明导入System.Text.RegularExpressions
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:
屏幕截图#2:
屏幕截图#3:
屏幕截图#4:
屏幕截图#5:
屏幕截图#6:
屏幕截图#7:
屏幕截图#8:
屏幕截图#9:
屏幕截图#10:
屏幕截图#11:
屏幕截图#12:
屏幕截图#13:
答案 2 :(得分:4)
我刚刚遇到这个问题,在阅读了一些回复之后,没有什么能真正解决我的问题,而且这里的解决方案在复杂性方面似乎很疯狂。
我的FTP任务失败,因为我不允许覆盖文件,假设作业连续两次启动,第一次传递会没问题,因为某些文件已经转移但如果本地文件已经存在则会失败。
我的解决方案很简单:
答案 3 :(得分:3)
(我不能接受我自己的答案,但这是对我有用的解决方案。)
这可能不是最佳解决方案,但这可行。
我使用脚本任务,并为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()
然后,在给它足够的时间关闭之后,我开始执行ftp命令的过程:
ftpParameters = "-s:" & ftpParameterLoc & ftpParameterFile & " " & ftpServer
proc = System.Diagnostics.Process.Start("ftp", ftpParameters)
然后,在给它更多的时间让ftp进程运行之后,我删除了临时的ftp文件(其中包含连接信息!)。
如果源目录中不存在文件(变量具有\\ drive \ dir \ *。*映射),则没有错误。如果发生其他错误,任务仍然会失败,应该如此。
我是SSIS的新手,这可能是一个混乱。但它现在有效。我想我问过最好的方法,我肯定不会说这就是它。
正如我所指出的,我无法知道文件的名称,或者根本没有任何文件。如果他们在那里,我想得到他们。
答案 4 :(得分:1)
我没有给你打包的答案,但是因为还没有其他人发布任何内容......
您应该能够在ActiveX脚本任务中设置变量,然后使用它来决定是否应该运行FTP任务。有一个示例here适用于本地路径。希望您能够调整概念(或者如果可能的话,映射FTP驱动器并按照这种方式进行)。
答案 5 :(得分:1)
1)设置FTP任务属性ForceExecutionResult = Success
2)将此代码添加到FTP Task 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;
}
答案 6 :(得分:0)
将它放在ForEach容器中,该容器迭代要上载的文件。没有文件,没有FTP,没有失败。
答案 7 :(得分:0)
您可以将失败重定向到另一个不执行任务的任务,即只返回true的脚本。
要执行此操作,请添加新脚本任务,突出显示您的FTP任务,将出现第二个绿色连接器,将其拖动到脚本任务,然后双击它。在“值”下拉列表中选择“失败”。显然,您需要处理此脚本任务中的实际故障,以便仍然显示在作业历史记录中。
答案 8 :(得分:0)
要下载X个文件,您可以采用两种方式,既可以在脚本任务中完全使用.Net,也可以使用.Net脚本任务中的文件名填充ArrayList,然后使用ForEach在ArrayList上,将文件名传递给变量并在标准FTP任务中下载该变量名。
适合的代码示例:http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=2472491&SiteID=1
因此,在上面,您将获取FileNames()并从中填充ArrayList,然后将ArrayList分配给Dts.Variables中的Object类型变量,然后使用代码将ForEach分配给Object(ArrayList)变量喜欢:http://www.sqlservercentral.com/articles/SSIS/64014/
答案 9 :(得分:0)
您可以使用eaSkills提供的免费SSIS FTP Task ++。如果文件不存在,它不会引发错误,它支持通配符,并且如果您需要,可以选择下载和删除。
以下是功能页面的链接: http://www.easkills.com/ssis/ftptask
答案 10 :(得分:0)
这是另一个适用于我的解决方案,使用内置的东西,因此无需手动重写FTP逻辑:
1)在包中创建一个名为FTP_Error
的变量2)单击您的FTP任务,然后单击“事件处理程序”选项卡
3)在页面中单击以创建“FTP Task / OnError”的事件处理程序 - 只要FTP出现问题就会触发
4)从工具箱中,拖动“脚本任务”项,然后双击打开它
5)在第一个弹出窗口中,ReadOnlyVariables - 添加System :: ErrorCode,System :: ErrorDescription
6)在第一个弹出窗口中,ReadWriteVariables - 添加你的User :: FTP_Error变量
7)编辑脚本
8)在脚本中设置你的FTP_Error变量来保存我们上面的ReadOnlyVariables:
Dts.Variables["FTP_Error"].Value = "ErrorCode:" + Dts.Variables["ErrorCode"].Value.ToString() + ", ErrorDescription=" + Dts.Variables["ErrorDescription"].Value.ToString();
9)保存并关闭脚本
10)点击“OK”进行脚本任务
11)返回“控制流程”选项卡
12)在FTP任务中,OnError转到新的脚本任务,然后编辑
13)ReadOnlyVariables:之前的用户:: FTP_Error
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;
}
从那里你的成功/失败的流程会做你想做的事情。
答案 11 :(得分:0)
另一种方法是使用此FTP File Enumerator