微軟BI 之SSIS 系列 - 在 SSIS 中將指定目錄下的所有文件分類輸出到不同文件夾


開篇介紹

比如有這樣的一個需求,舊的一個業務系統通常將產出的文件輸出到同一個指定的目錄下的不同子目錄,輸出的文件類型有 XML,EXCEL, TXT 這些不同后綴的文件。現在需要在 SSIS 中將它們分類整理到不同的文件夾下,比如 XML 的全部拷貝到 A 文件夾, EXCEL 全部拷貝到 B 文件夾。 

案例分析

其實文件操作在 C# 中直接編程可能更好解決,不需要特別多的代碼就可以完成這個拷貝的任務。SSIS 中比 C# 編程優勢的地方可以體現在 SSIS 可以直接解析文件並作為數據源輸出到指定的目的地中,比如平面文件,EXCEL 或者數據庫等。包括數據拆分,異常捕獲,錯誤數據處理等,涉及到流程控制部分還是會優先選擇 SSIS 。

但是在這里通過這樣的一個 SSIS 小例子來掌握一下在 SSIS 中如何獲取指定目錄下的所有文件,以及如何拷貝文件的操作。並且,在這個例子中還介紹了如何在 Control Flow 中在沒有先決條件的情況下主動給自己創造一個先決條件等小技巧。

具體問題具體對待,這個例子在實際使用中並不合理,再次強調! 但是可以從這個例子中選擇部分處理技巧或者處理方式延用到實際項目中,這個還是完全可以的。

案例實現的過程

新建一個包並創建以下變量 -

DestinationDirectory - 輸出的目的地文件夾,將根據文件后綴決定。比如如果文件后綴是 .txt 那么就輸出到 TXTFileDirectory 變量指定的文件夾下;如果文件是 .xml 類型,那么就輸出到 XMLFileDirectory 變量指定的文件夾下。

它的 Expression 表達式 -

FINDSTRING( @[User::FileName],".txt",1)!=0? @[User::TXTFileDirectory]:(FINDSTRING( @[User::FileName],".xml",1)!=0? @[User::XMLFileDirectory] : "")

Directory - 源文件夾

FileExtensionFilter - 為了演示這個例子,我們假設要循環獲取 Directory 目錄下的所有文件 *.*,然后在這些文件中選擇 .txt 和 .xml 后綴的文件拷貝到指定目錄下。

技巧一 - 如何獲取指定目錄下所有文件名稱

  • FileName - 文件的名稱
  • FileNames - 獲取所有的文件名稱集合,這個集合注意是 Object 類型的 - 使用 SSIS 中的 Foreach Loop Container 是可以遍歷數組的。

技巧二 - 在循環遍歷的數組類型在 SSIS 用什么數據類型表示 - OBJECT

  • IsTopDirectory - 是否只在當前目錄中查找,0 - 當前目錄,非0 - 當前目錄以及所有子目錄

在控制流中編輯 Script Task - SCR_LoadAllFiles, 要分得清楚哪些是只讀的,哪些是需要修改值 - 可讀寫類型。

記得引用 System.IO 命名空間,在 MAIN 方法中的代碼 -

public void Main()
        {
            string directory = Dts.Variables["User::Directory"].Value.ToString();
            int isTopDirectory = Int16.Parse(Dts.Variables["User::IsTopDirectory"].Value.ToString());
            string extension = Dts.Variables["User::FileExtensionFilter"].Value.ToString();
            // TODO: Add your code here

            if (isTopDirectory == 0)
            {
                Dts.Variables["User::FileNames"].Value = Directory.GetFiles(directory, extension, SearchOption.TopDirectoryOnly);
            }
            else 
            {
                Dts.Variables["User::FileNames"].Value = Directory.GetFiles(directory, extension, SearchOption.AllDirectories);
            }
             
            Dts.TaskResult = (int)ScriptResults.Success;
        }

Foreach Loop Container 中 - 選擇 Foreach From Variable Enumerator 這樣就可以遍歷一個數組集合了。

每次循環從 FileNames 集合中取到的一個文件名就賦值給 FileName。

下面要做的操作是 - 在循環中根據文件的后綴的不同拷貝到不同的文件夾。由於文件夾下可能有除了 .xml 和 .txt 之外的很多文件,因此在這里需要判斷如果不是 .xml 和 .txt 文件類型的就忽略拷貝動作。

問題在於:在控制流 Control Flow Task 中並沒有像 Data Flow Task 數據流中所具有的像 Conditional Split 等控件,所以這里只能使用流程中的 Precedence Constraint 先決條件或者叫做先決約束來控制。

由於在 Copy Files to Directory 這個 File System Task 本身不具備這種過濾操作,因此主動的在它的前面添加一個 Expression Task 然后就可以使用 Precedence Constraint 了,實際上這個 Expression Task 本身不處理任何操作。

技巧三 - 如何在沒有上游控件輸出的情況下,在控制流中實現條件判斷處理

Expression Task 中可以隨便拖放一個變量 -

關鍵的還是在連接 Cope Files To Directory 的那條線上我們要編輯條件 -

在最開始定義 DestinationDirectory 變量的時候已經介紹過了,它的值是由其它變量決定的。這里,在每次循環的時候都可以拿到 FileName 文件名,然后如果在文件名中能查找到 .txt 那么 DestinationDirectory 的值就等於 TxtFileDirectory 的值,后面同理。如果都找不到,那么就等於空字符串。所以上面的判斷就體現這樣的邏輯,只有后綴是 .txt 或者 .xml 結尾的文件才會進入到下一步被處理。

在 Copy Files to Directory (File System Task) 中 先選擇 Operation 然后再配置其它操作 -

當然 File System Task 不僅僅只可以用來操作 Cope Files,還有其它很多很多操作 -

最后保存執行 Package,它會遍歷所有的子目錄並獲取所有的文件名稱。

來自不同目錄下的所有 .txt 文件集中到一個文件夾下。

來自不同目錄的 .xml 文件集中到一個目錄下。

那么利用上面的這些文件處理控件包括遍歷等到底可以實現什么具體功能? 有一個需求可能會存在 - 就是有一個 JOB ,每天執行一次,然后監視一下指定目錄下文檔的變化情況,將變化的情況寫入數據庫表中,或者做成報表,可以非常容易的看到那些是今天新增加的文件,哪些文件發生了改變等等。

更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM