2011-03-16 161 views
12

有一個非常簡單的SSIS包:SSIS - 平面文件總是ANSI從未UTF-8編碼

  • OLE DB源通過視圖獲取數據,(在數據庫表nvarchar的所有字符串列或NCHAR)。
  • 派生列將現有日期格式化並將其添加到數據集(數據類型DT_WSTR)。
  • 組播任務分裂之間的數據集:
    • OLE DB命令來更新行作爲「加工」。
    • 平面文件目標 - 連接管理器設置爲代碼頁65001 UTF-8和Unicode未選中。所有字符串列都映射到DT_WSTR。

每次我運行此包在記事本++其ANSI開放平面文件,從未UTF-8。如果我檢查Unicode選項,該文件是UCS-2 Little Endian。

我做錯了什麼 - 我怎樣才能得到平面文件是UTF-8編碼?

感謝

+0

確定 - 在[SQL Server論壇]上似乎找到了可以接受的解決方法(http://social.msdn.microsoft.com/forums/en-us/sqlintegrationservices/thread/9B68C357-A5B4-47BF-8EFD -A05945210CA2)。 本質上,我必須創建兩個UTF-8模板文件,使用文件任務將它們複製到我的目標,然後確保我正在追加數據而不是覆蓋。 – Neil

+1

隨時回答你的問題,然後標記它。 – Sam

回答

0

OK - 似乎對SQL Server Forums一個可接受的變通找到。基本上我必須創建兩個UTF-8模板文件,使用文件任務將它們複製到我的目標,然後確保我正在追加數據而不是覆蓋。

20

在源代碼 - >高級編輯 - >組件屬性 - > 設置默認代碼頁65001 AlwaysUseDefaultCodePage爲True

然後源 - >高級編輯 - >輸入和輸出屬性 入住外部列每列和OutPut Columns,並儘可能將CodePage設置爲65001。

就是這樣。

順便說一下,Excel無法將文件內的數據定義爲UTF-8 .Excel只是一個文件處理程序。您也可以使用記事本創建csv文件。只要你用UTF-8填充CSV文件,你應該沒問題。

+2

在源代碼 - >高級編輯器 - >組件屬性 - >將默認代碼頁設置爲65001 AlwaysUseDefaultCodePage爲True,這一步幫助我節省數小時尋找雙重代碼頁參考錯誤 – BigChief

+1

請注意,這不適用於NVARCHAR(MAX)列,但如果您的查詢轉換爲NVARCHAR(4000),則它可以工作。如果您的查詢在字段中需要> 4000個字符,請嘗試腳本組件或其他解決方案之一。 – NYCdotNet

5

添加解釋的答案...

設置代碼頁65001(但不檢查文件源上的Unicode的複選框),應該產生一個UTF-8文件。 (是的,內部的數據類型也應該是nvarchar等)。

但是,從SSIS生成的文件沒有BOM頭(字節順序標記),因此有些程序會認爲它仍然是ASCII,而不是UTF-8。我已經看到這個由MS員工確認的MSDN,以及通過測試證實。

文件附加解決方案是一種解決方法 - 通過創建具有適當BOM的空白文件,然後從SSIS追加數據,BOM表頭保持原位。如果你告訴SSIS覆蓋文件,它也會丟失BOM。

感謝這裏的提示,它幫助我弄清楚了上述細節。

4

我已經在這裏我們遇到的情況,如下面的一個問題最近工作:

您在使用SQL Server集成服務(Visual Studio 2005中)溶液工作。 您正在從數據庫中提取數據,並嘗試將結果放入UTF-8格式的平面文件(.CSV)中。該解決方案將數據完美地導出並保留文件中的特殊字符,因爲您已使用65001作爲代碼頁。

但是,當您打開文本文件或嘗試將其加載到另一個進程時,它表示該文件是ANSI而不是UTF-8。如果您在記事本中打開文件並執行SAVE AS並將編碼更改爲UTF-8,然後您的外部過程可以工作,但這是一項繁瑣的手動工作。

我發現當您指定Flat文件連接管理器的代碼頁屬性時,它會生成一個UTF-8文件。但是,它會生成一個UTF-8文件的版本,它錯過了我們稱之爲「字節順序標記」的內容。

因此,如果您有包含字符AA的CSV文件,則UTF8的BOM將爲0xef,0xbb和0xbf。即使該文件沒有BOM,它仍然是UTF8。

不幸的是,在一些舊的遺留系統中,應用程序搜索BOM以確定文件的類型。看來你的過程也是這樣做的。

要解決該問題,您可以在腳本任務中使用以下代碼片段,該代碼片段可以在導出過程後運行。

using System.IO; 

using System.Text; 

using System.Threading; 

using System.Globalization; 

enter code here 

static void Main(string[] args) 
     { 
      string pattern = "*.csv"; 
      string[] files = Directory.GetFiles(@".\", pattern, SearchOption.AllDirectories); 
      FileCodePageConverter converter = new FileCodePageConverter(); 
      converter.SetCulture("en-US"); 
      foreach (string file in files) 
      { 
       converter.Convert(file, file, "Windows-1252"); // Convert from code page Windows-1250 to UTF-8 
      } 
     } 

class FileCodePageConverter 
    { 
     public void Convert(string path, string path2, string codepage) 
     { 
      byte[] buffer = File.ReadAllBytes(path); 
      if (buffer[0] != 0xef && buffer[0] != 0xbb) 
      { 
       byte[] buffer2 = Encoding.Convert(Encoding.GetEncoding(codepage), Encoding.UTF8, buffer); 
       byte[] utf8 = new byte[] { 0xef, 0xbb, 0xbf }; 
       FileStream fs = File.Create(path2); 
       fs.Write(utf8, 0, utf8.Length); 
       fs.Write(buffer2, 0, buffer2.Length); 
       fs.Close(); 
      } 
     } 

     public void SetCulture(string name) 
     { 
      Thread.CurrentThread.CurrentCulture = new CultureInfo(name); 
      Thread.CurrentThread.CurrentUICulture = new CultureInfo(name); 
     } 
    } 

當你將運行包你會發現,在指定的文件夾中所有的CSV將被轉換成包含字節順序標記的UTF8格式。

通過這種方式,您的外部進程將可以使用導出的CSV文件。

,如果你只是在尋找特定的文件夾...發送變量腳本任務,並使用下面的..

 string sPath; 

     sPath=Dts.Variables["User::v_ExtractPath"].Value.ToString(); 

     string pattern = "*.txt"; 

     string[] files = Directory.GetFiles(sPath); 

我希望這有助於!

+0

我正在開發一個項目,將CSV文件交給Linux團隊,最終將他們加載到MySQL倉庫中。你的方法是唯一爲他們工作的方法。你的代碼工作,我只添加參數化。任何嘗試創建加載沒有SSIS板載問題的UTF-8編碼文件都是不成功的。 – cdonner