web-dev-qa-db-ja.com

ダウンロードするファイルがないときにSSIS FTPタスクが失敗しないようにするにはどうすればよいですか?

SQL Server 2005を使用しており、SSIS内でFTPタスクを作成しています。

Ftpで転送するファイルがある場合とない場合があります。ファイルがない場合、タスクもパッケージも失敗しないようにします。矢印をftpタスクから次の「完了」に変更して、パッケージが実行されるようにしました。エラーの許容数を4に変更しました(4つのftpタスクがあり、4つのディレクトリのいずれにもファイルがある場合とない場合があるため)。

しかし、エージェントのジョブからパッケージを実行すると、ジョブは失敗としてマークされます。これは15分ごとに実行されるので、ジョブ履歴に大量の赤いXを表示したくないので、実際に問題が発生しても問題が発生しません。

FTPでファイルを見つけられないことが失敗にならないように、FTPタスクでプロパティを設定するにはどうすればよいですか?使用している操作は「ファイル送信」です。

次に、いくつかの詳細情報を示します。ファイルは、ftp以外のアクセス権がないサーバーにあります。そして、私は事前にファイル名を知りません。ユーザーは好きなようにそれらを呼び出すことができます。そのため、特定のファイルを確認することも、まったく確認することもできません。 FTP接続とその接続に基づくタスクを使用する場合を除きます。ファイルはリモートサーバーにあり、それらを自分のサーバーにコピーして、そのリモートサーバーから取得します。

スクリプトタスクでコマンドレベルのFTPをシェル化できます。おそらく、それがftpタスクの代わりに使用する必要があるものです。 (スクリプトタスクから呼び出されるパラメーターファイルを使用してftpコマンドラインを使用するように変更しました。取得するファイルがない場合でもエラーは発生しません。このソリューションはうまくいくと思います。パラメータファイルを動的に使用します。つまり、プレーンテキストファイルに接続情報を含める必要はなく、より安全な場所にある構成ファイルに保存できます。)

18
thursdaysgeek

質問に対する回答が見つかったとのこと、承知いたしました。これは、この質問に遭遇する可能性のある他のユーザー向けです。これを実現する方法の1つを次に示します。 Script Taskを使用して、特定のパターンのFTPフォルダパスに存在するファイルのリストを検索できます(たとえば、*.txt)。以下の例は、これを行う方法を示しています。

ステップバイステッププロセス:

  1. SSISパッケージで、 [〜#〜] ftp [〜#〜] という名前のFTP Connectionを作成し、 5 変数を次のように作成しますスクリーンショット# 1 。変数RemotePathにはFTPフォルダーのパスが含まれます。 LocalPathには、ファイルのダウンロード先フォルダーが含まれます。 FilePatternには、FTPサーバーからダウンロードするファイルのリストを見つけるためのファイルパターンが含まれています。 FileNameForeach loop containerによって入力されますが、FTPタスクの設計時エラーを回避するために、 /またはFTPのDelayValidationプロパティを入力できますタスクは True に設定できます。

  2. スクリーンショット# 2 に示すように、SSISパッケージでScript Task内にForeach Loop containerFTP TaskForeach Loop containerを配置します。

  3. Script Task内のMain()メソッドを Script Task Code セクションのコードに置き換えます。スクリプトタスクは、変数 ListOfFiles に、指定されたパターンに一致するファイルのコレクションを入力します。この例では、最初にパターン* .txtを使用しますが、結果は得られません。その後、パターン* .xlsがFTPサーバー上のいくつかのファイルと一致します。

  4. スクリーンショット# 3 および# 4 に示すように、Foreach Loop containerを構成します。このタスクは、変数** ListOfFiles *をループします。ファイルがない場合、ループコンテナー内のFTPタスクは実行されません。ファイルがある場合、ループコンテナー内のFTPタスクは、FTPサーバーで見つかったファイルの数のタスクに対して実行されます。

  5. スクリーンショット# 5 および# 6 に示すように、FTP Taskを構成します。

  6. スクリーンショット# 7 は、パターン*.txt no 一致するファイルが見つかった場合のサンプルパッケージ実行を示しています。

  7. スクリーンショット# 8 は、フォルダーの内容C:\temp\ before パッケージの実行を示しています。

  8. スクリーンショット# 9 は、パターン*.xlsで一致するファイルが見つかった場合のパッケージの実行例を示しています。

  9. スクリーンショット# 10 は、FTPリモートパス/Practice/Directory_Newの内容を示しています。

  10. スクリーンショット# 11 は、フォルダーの内容C:\temp\ after パッケージの実行を示しています。

  11. スクリーンショット# 12 は、誤った Remote path を指定した場合のパッケージの失敗を示しています。

  12. スクリーンショット# 13 は、パッケージの失敗に関連するエラーメッセージを示しています。

お役に立てば幸いです。

スクリプトタスクコード:

C#SSIS 2008 and aboveで使用できるコード。

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;
}

[〜#〜] vb [〜#〜] SSIS 2005 and aboveで使用できるコード。

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

スクリーンショット#1:

1

スクリーンショット#2:

2

スクリーンショット#3:

3

スクリーンショット#4:

4

スクリーンショット#5:

5

スクリーンショット#6:

6

スクリーンショット#7:

7

スクリーンショット#8:

8

スクリーンショット#9:

9

スクリーンショット#10:

10

スクリーンショット#11:

11

スクリーンショット#12:

12

スクリーンショット#13:

13

14
user756519

SSISパッケージでのタスクエラーの適切な処理について説明しているこの link を確認してください。

私はほぼ同じ問題を抱えていましたが、ファイルの取得に関してです。 FTPサーバーでファイルが見つからない場合でも、パッケージが失敗しないようにしたいと思いました。上記のリンクにより、エラーが発生してパッケージが失敗するのを防ぎます。 FailPackageOnError = falseを実行する必要があると思いましたか? :-S

これがあなたのためにもそれを解決することを願っています!

14
Rich

ここでいくつかの返信を読んだ後、私はこの問題を抱えていましたが、実際に私の問題を整理するものは何もありません。

ファイルの上書きを許可しなかったため、FTPタスクが失敗しました。たとえば、ジョブが2回続けて開始されたとします。最初のパスは問題ありません。一部のファイルは転送されますが、ローカルファイルがすでに存在する場合は失敗します。

私の解決策は簡単でした:

  1. タスクを右クリック-プロパティ
  2. ForceExecutionResult = "成功"を設定します
4
tribe84

(私は自分の答えを受け入れることはできませんが、これは私のために働いた解決策でした。)

それは最善の解決策ではないかもしれませんが、これは機能します。

私はスクリプトタスクを使用しており、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を初めて使用するので、これは行き詰まりかもしれません。しかし、それは今のところ機能します。私は最良の方法を求めたと思います、そして私は確かにこれがそれであると主張しません。

指摘したように、ファイルの名前を知る方法はありません。ファイルが存在するかどうかさえもわかりません。彼らがそこにいるなら、私は彼らを手に入れたいです。

3
thursdaysgeek

パッケージ化された回答はありませんが、まだ誰も投稿していないので...

ActiveXスクリプトタスクで変数を設定し、それを使用してFTPタスクを実行するかどうかを決定できるはずです。ローカルパスで機能する例 here があります。うまくいけば、概念を適合させることができます(または、可能であれば、FTPドライブをマップして、そのようにしてください)。

1
Tom H

1)FTPタスクプロパティForceExecutionResult = Successを設定します

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;
    }
1
Todd Hoffert

それをForEachコンテナーに入れ、アップロードするファイルを反復処理します。ファイルなし、FTPなし、失敗なし。

0
Meff

これは、組み込みのものを使用するなど、FTPロジックを手動で書き直すことなく機能する別のソリューションです。

1)FTP_Errorという変数をパッケージに作成します

2)FTPタスクをクリックし、[イベントハンドラ]タブをクリックします。

3)ページ内をクリックして、「FTPタスク/ OnError」のイベントハンドラーを作成します。これは、FTPに問題があるときに起動します

4)ツールボックスからスクリプトタスクアイテムをドラッグし、ダブルクリックして開きます

5)最初のポップアップで、ReadOnlyVariables-System :: ErrorCode、System :: ErrorDescriptionを追加します。

6)最初のポップアップで、ReadWriteVariables-User :: FTP_Error変数を追加します。

7)スクリプトを編集

8)スクリプトで、上記のReadOnlyVariablesを保持するようにFTP_Error変数を設定します。

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

9)スクリプトを保存して閉じます

10)スクリプトタスクに[OK]を押します

11)「制御フロー」タブに戻ります

12)OnErrorはFTPタスクから新しいスクリプトタスクに移動し、それを編集します

13)ReadOnlyVariables:以前のUser :: 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;
}

そして、そこから、成功/失敗フローは、それを使ってやりたいことを実行します。

0
Chad

失敗した場合は、何もしない別のタスク、つまりtrueを返すだけのスクリプトにリダイレクトできます。

これを行うには、新しいスクリプトタスクを追加し、FTPタスクを強調表示します。2番目の緑色のコネクタが表示され、これをスクリプトタスクにドラッグしてから、ダブルクリックします。 [値]ドロップダウンで[失敗]を選択します。もちろん、ジョブ履歴に正しく表示するには、このスクリプトタスクで実際のエラーを処理する必要があります。

0
baldy

EaSkillsから無料のSSIS FTP Task ++を使用できます。ファイルが存在しない場合でもエラーはスローされません。ワイルドカードがサポートされており、必要に応じてダウンロードして削除することができます。

ここに機能ページへのリンクがあります: http://www.easkills.com/ssis/ftptask

0
Kilani

別の方法はこれを使用することです FTP File Enumerator enter image description here

0
Joost

Aha、OK-説明してくれてありがとう。 FTPタスクはフォルダーリストを返すことができないため、最初に述べたようにForEachを使用することはできません。これは、XソースのファイルにX個のファイルをアップロードする場合にのみ機能します。

X個のファイルをダウンロードするには、2つの方法があります。スクリプトタスクで完全に.Netで行う方法と、.Netスクリプトタスク内からArrayListにファイル名を入力してから、ArrayListでForEachを実行する方法です。 、ファイル名を変数に渡し、その変数名を標準のFTPタスクでダウンロードします。

適切なコード例: http://forums.Microsoft.com/msdn/ShowPost.aspx?PostID=2472491&SiteID=1

したがって、上記では、FileNames()を取得し、そこからArrayListにデータを入力してから、ArrayListをDts.Variablesのオブジェクト型変数に割り当て、そのオブジェクト(ArrayList)変数に対してForEachを次のようなコードを使用して割り当てます。 http://www.sqlservercentral.com/articles/SSIS/64014/

0
Meff