J'utilise SQL Server 2005 et crée des tâches ftp dans SSIS.
Parfois, il y aura des fichiers sur lesquels ftp over, parfois non. S'il n'y a pas de fichiers, je ne veux pas que la tâche ni le package échouent. J'ai changé la flèche allant de la tâche ftp à la suivante en "complétion", ainsi le paquet est exécuté. J'ai changé le nombre autorisé d'erreurs à 4 (car il y a 4 tâches ftp, et n'importe lequel des 4 répertoires peut contenir ou non des fichiers).
Mais, lorsque je lance le package à partir d'un travail dans l'agent, le travail échoue. Comme cela fonctionnera toutes les 15 minutes, je ne veux pas qu'il y ait beaucoup de x rouges dans mon historique de travail, ce qui nous évitera de voir un problème lorsqu'il se produit réellement.
Comment définir les propriétés dans la tâche ftp pour que la recherche de fichiers au format FTP ne soit pas un échec? L'opération que j'utilise est "Envoyer des fichiers".
Voici quelques informations supplémentaires: les fichiers se trouvent sur un serveur auquel je n’ai accès que par ftp. Et, je ne connais pas les noms de fichiers à l'avance. L'utilisateur peut les appeler comme ils veulent. Je ne peux donc pas vérifier des fichiers spécifiques, ni, je pense, du tout. Sauf en utilisant la connexion ftp et les tâches basées sur cette connexion. Les fichiers se trouvent sur un serveur distant et je souhaite les copier sur mon serveur pour les obtenir à partir de ce serveur distant.
Je peux Shell un ftp de niveau commande dans une tâche de script. C’est peut-être ce que j’ai besoin d’utiliser au lieu d’une tâche ftp. (J'ai changé pour utiliser la ligne de commande ftp, avec un fichier de paramètres, appelé à partir d'une tâche de script. Il ne génère aucune erreur s'il n'y a pas de fichiers à récupérer. Je pense que cette solution fonctionnera pour moi. fichier de paramètres dynamiquement, ce qui signifie que je n'ai pas besoin d'informations de connexion dans le fichier texte brut, mais que je peux plutôt le stocker dans mon fichier de configuration, qui se trouve dans un emplacement plus sécurisé.)
Je comprends que vous ayez trouvé une réponse à votre question. Ceci est destiné aux autres utilisateurs qui pourraient trébucher sur cette question. Voici un moyen possible d'y parvenir. Script Task
peut être utilisé pour trouver la liste des fichiers présents dans un chemin de dossier FTP pour un modèle donné (par exemple *.txt
). L'exemple ci-dessous montre comment cela peut être fait.
Processus pas à pas:
Sur le package SSIS, créez un FTP Connection
nomméFTPet créez également les variables 5 comme indiqué dans la capture d'écran n ° 1 . La variable RemotePath
contient le chemin du dossier FTP; LocalPath
contient le dossier dans lequel les fichiers seront téléchargés; FilePattern
contient le modèle de fichier permettant de trouver la liste des fichiers à télécharger à partir du serveur FTP; FileName
sera renseigné par le Foreach loop container
, mais pour éviter toute erreur de temps de conception d'une tâche FTP, il peut être rempli avec/ou la propriété DelayValidation
de la tâche FTP peut être définie sur True .
Sur le package SSIS, placez un Script Task
, Foreach Loop container
et FTP Task
dans le Foreach Loop container
, comme indiqué dans les captures d'écran # 2 .
Remplacez la méthode Main()
dans le Script Task
par le code situé dans la section Code de tâche de script . La tâche de script remplira la variable ListOfFiles avec la collection de fichiers correspondant à un modèle donné. Cet exemple utilisera d’abord le motif * .txt, qui ne donne aucun résultat, puis le motif * .xls qui correspondra à quelques fichiers sur le serveur FTP.
Configurez le Foreach Loop container
comme indiqué dans les captures d’écran # 3 et # 4 . Cette tâche effectuera une boucle dans la variable ** ListOfFiles *. S'il n'y a pas de fichiers, la tâche FTP à l'intérieur du conteneur de boucles ne s'exécutera pas. S'il y a des fichiers, la tâche FTP à l'intérieur du conteneur de boucles s'exécutera pour la tâche en fonction du nombre de fichiers trouvés sur le serveur FTP.
Configurez le FTP Task
comme indiqué dans les captures d'écran # 5 et # 6 .
La capture # 7 montre un exemple d’exécution du paquet lorsque no des fichiers correspondants sont trouvés pour le modèle *.txt
.
La capture d'écran # 8 montre le contenu du dossier C:\temp\
before exécution du paquet.
La capture # 9 montre un exemple d’exécution de paquet lorsque des fichiers correspondants sont trouvés pour le modèle *.xls
.
La capture d'écran # 10 montre le contenu du chemin d'accès distant FTP /Practice/Directory_New
.
La capture d'écran # 11 montre le contenu du dossier C:\temp\
après exécution du paquet.
La capture d'écran # 12 montre l'échec du package s'il est fourni avec un chemin incorrect Remote .
La capture d'écran # 13 affiche le message d'erreur lié à l'échec du package.
J'espère que cela pourra aider.
Code de tâche de script:
C # code pouvant être utilisé dansSSIS 2008 and above
.
Incluez l'instruction using
using System.Text.RegularExpressions;
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;
}
VBcode pouvant être utilisé dansSSIS 2005 and above
.
Incluez l'instruction Imports
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
Capture d'écran n ° 1:
Capture d'écran n ° 2:
Capture d'écran n ° 3:
Capture d'écran n ° 4:
Capture d'écran n ° 5:
Capture d'écran n ° 6:
Capture d'écran # 7:
Capture d'écran # 8:
Capture d'écran # 9:
Capture d'écran # 10:
Capture d'écran # 11:
Capture d'écran # 12:
Capture d'écran # 13:
Cochez cette link qui décrit la gestion des erreurs de tâche dans le package SSIS.
J'ai eu presque le même problème mais, avec la récupération de fichiers. Je voulais que le paquet n'échoue PAS lorsqu'aucun fichier n'a été trouvé sur le serveur FTP. Le lien ci-dessus empêche l'erreur de se propager et de provoquer l'échec du package; quelque chose que vous auriez pensé que FailPackageOnError = false aurait dû faire? : -S
J'espère que cela résoudra les problèmes pour vous aussi!
Je viens d'avoir ce problème, après avoir lu certaines des réponses ici, rien ne résout vraiment mon problème et les solutions ici semblent insensées en termes de complexité.
Ma tâche FTP échouait depuis que je n'autorisais pas l'écrasement des fichiers. Disons que le travail a été lancé deux fois de suite. Le premier passage sera correct, car certains fichiers sont transférés mais échoueront si un fichier local existe déjà.
Ma solution était simple:
(Je ne peux pas accepter ma propre réponse, mais c'est la solution qui a fonctionné pour moi.)
Ce n'est peut-être pas la meilleure solution, mais cela fonctionne.
J'utilise une tâche de script et dispose de nombreuses variables pour les informations de connexion FTP, ainsi que pour les répertoires source et de destination. (Parce que nous allons changer le serveur sur lequel il est exécuté et il sera plus facile de changer dans un paquet de configuration.)
Je crée un fichier texte à la volée et lui écrit les commandes 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()
Puis, après lui avoir laissé suffisamment de temps pour fermer, je lance un processus pour exécuter la commande ftp:
ftpParameters = "-s:" & ftpParameterLoc & ftpParameterFile & " " & ftpServer
proc = System.Diagnostics.Process.Start("ftp", ftpParameters)
Puis, après avoir laissé un peu plus de temps au processus ftp, je supprime le fichier ftp temporaire (qui contient des informations de connexion!).
Si les fichiers n'existent pas dans le répertoire source (la variable a le mappage \\ lecteur\dir\*. *), Il n'y a pas d'erreur. Si une autre erreur se produit, la tâche échoue toujours, comme il se doit.
Je suis nouveau à SSIS, et cela peut être un kludge. Mais ça marche pour le moment. Je suppose que j'ai demandé le meilleur moyen, et je ne prétends certainement pas que c'est ça.
Comme je l'ai souligné, je n'ai aucun moyen de savoir comment les fichiers sont nommés, ni même s'il y a des fichiers. S'ils sont là, je veux les avoir.
Je n'ai pas de réponse packagée pour vous, mais comme personne d'autre n'a encore rien posté ...
Vous devriez pouvoir définir une variable dans une tâche de script ActiveX, puis l'utiliser pour décider si la tâche FTP doit être exécutée ou non. Il y a un exemple ici qui fonctionne avec les chemins locaux. Espérons que vous pourrez adapter le concept (ou, si possible, mapper le lecteur FTP et le faire de cette façon).
1) Définissez la propriété de la tâche FTP ForceExecutionResult = Success
2) Ajoutez ce code au gestionnaire d'événements OnError de la tâche FTP.
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;
}
Placez-le dans un conteneur ForEach, qui itère sur les fichiers à télécharger. Pas de fichiers, pas de FTP, pas d'échec.
C'est une autre solution qui fonctionne pour moi, en utilisant des outils intégrés et donc sans réécrire manuellement la logique FTP:
1) Créez une variable dans votre paquetage appelée FTP_Error
2) Cliquez sur votre tâche FTP, puis sur l'onglet "Gestionnaires d'événements".
3) Cliquez dans la page pour créer un gestionnaire d’événements pour "FTP Task/OnError" - il se déclenchera chaque fois qu’un problème survient avec FTP
4) Dans la boîte à outils, faites glisser un élément de tâche de script et double-cliquez dessus pour l'ouvrir.
5) Dans la première fenêtre contextuelle, ReadOnlyVariables - ajoutez System :: ErrorCode, System :: ErrorDescription
6) Dans la première fenêtre contextuelle, ReadWriteVariables - ajoutez votre variable User :: FTP_Error
7) Modifier le script
8) Dans le script, définissez votre variable FTP_Error pour contenir les ReadOnlyVariables ci-dessus:
Dts.Variables["FTP_Error"].Value = "ErrorCode:" + Dts.Variables["ErrorCode"].Value.ToString() + ", ErrorDescription=" + Dts.Variables["ErrorDescription"].Value.ToString();
9) Sauvegarder et fermer le script
10) Appuyez sur "OK" pour la tâche de script
11) Retournez à l'onglet "Flux de contrôle"
12) À partir de la tâche FTP, OnError va à une nouvelle tâche de script et édite celle-ci.
13) ReadOnlyVariables: User :: FTP_Error d'avant
14) Maintenant, quand aucun fichier ne se trouve sur le FTP, le code d'erreur est -1073573501 (Vous pouvez trouver la liste de référence des codes d'erreur ici: http://msdn.Microsoft.com/en- us/library/ms345164.aspx )
15) Dans votre script, indiquez dans la logique de faire ce que vous voulez - si vous trouvez un code "aucun fichier trouvé", alors peut-être que vous dites que la tâche a réussi. Sinon, la tâche a échoué. Et votre flux normal peut gérer cela comme vous le souhaitez:
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;
}
Et à partir de là, votre flux Succeeded/Failed fera ce que vous voulez en faire.
Vous pouvez rediriger en cas d’échec, vers une autre tâche qui ne fait rien, c’est-à-dire un script qui renvoie simplement true.
Pour ce faire, ajoutez la nouvelle tâche de script, mettez en surbrillance votre tâche FTP, un deuxième connecteur vert apparaîtra, faites-le glisser sur la tâche de script, puis double-cliquez dessus. Sélectionnez Échec dans la liste déroulante Valeur. De toute évidence, vous devrez alors gérer les échecs réels dans cette tâche de script avant de les afficher directement dans l'historique des tâches.
Vous pouvez utiliser le logiciel gratuit SSIS FTP Task ++ de eaSkills. Il ne génère pas d'erreur si le ou les fichiers n'existent pas, il prend en charge les caractères génériques et vous offre la possibilité de télécharger et de supprimer le cas échéant.
Voici le lien vers la page de fonctionnalité: http://www.easkills.com/ssis/ftptask
Une alternative consiste à utiliser cet énumérateur FTP File Enumerator
Aha, OK - Merci pour la clarification. Comme la tâche FTP ne peut pas renvoyer une liste de dossiers, il ne sera pas possible d’utiliser le ForEach comme je l’ai dit au début - Cela ne fonctionne que si vous téléchargez X nombre de fichiers sur une source distante.
Pour télécharger une quantité X de fichiers, vous pouvez procéder de deux manières: soit vous le faites entièrement en .Net dans une tâche de script, soit vous pouvez renseigner une liste de tableaux avec les noms de fichiers contenus dans une tâche de script .Net, puis ForEach sur la liste de tableaux , en passant le nom du fichier à une variable et en téléchargeant ce nom dans une tâche FTP standard.
Exemple de code correspondant: http://forums.Microsoft.com/msdn/ShowPost.aspx?PostID=2472491&SiteID=1
Ainsi, dans ce qui précède, vous obtiendrez le FileNames () et remplirez le ArrayList à partir de cela, puis assigner le ArrayList à une variable de type Object dans Dts.Variables, puis ForEach sur cette variable Object (ArrayList) en utilisant un code du type: http://www.sqlservercentral.com/articles/SSIS/64014/