SSIS - 平面文件总是ANSI从不UTF-8编码

时间:2011-03-16 08:26:01

标签: utf-8 ssis flat-file

有一个非常简单的SSIS包:

  • OLE DB Source通过视图获取数据,(db table nvarchar或nchar中的所有字符串列)。
  • 派生列以格式化现有日期并将其添加到数据集中(数据类型DT_WSTR)。
  • 在以下各项之间拆分数据集的多播任务:
    • OLE DB命令将行更新为“已处理”。
    • 平面文件目标 - 其连接管理器设置为代码页面65001 UTF-8并取消选中Unicode。所有字符串列都映射到DT_WSTR。

每次我运行这个包时,在Notepad ++中打开它的ANSI平面文件,而不是UTF-8。如果我检查Unicode选项,则该文件是UCS-2 Little Endian。

我做错了什么 - 如何让平面文件成为UTF-8编码?

由于

6 个答案:

答案 0 :(得分:24)

来源 - >高级编辑 - >组件属性 - > 将默认代码页设置为65001 AlwaysUseDefaultCodePage为True

然后来源 - >高级编辑 - >输入和OutPut属性 检查外部列和OutPut列中的每列,并尽可能将CodePage设置为65001。

就是这样。

顺便说一句,Excel无法将文件中的数据定义为UTF - 8. Excel只是一个文件处理程序。您也可以使用记事本创建csv文件。只要你用UTF-8填充csv文件就可以了。

答案 1 :(得分:5)

为答案添加解释......

将CodePage设置为65001(但不检查文件源上的Unicode复选框),应生成UTF-8文件。 (是的,内部的数据类型也应该是nvarchar等)。

但是从SSIS生成的文件没有BOM头(字节顺序标记),所以有些程序会认为它仍然是ASCII,而不是UTF-8。我已经在MSDN上看到MS员工确认了这一点,并通过测试证实了这一点。

文件附加解决方案是解决此问题的方法 - 通过使用适当的BOM创建空白文件,然后从SSIS附加数据,BOM标头仍然存在。如果您告诉SSIS覆盖该文件,它也会丢失BOM。

感谢此处的提示,它帮助我弄清楚了上述细节。

答案 2 :(得分:4)

我最近遇到了一个问题,我们遇到了以下情况:

您正在使用SQL Server Integration Services(Visual Studio 2005)开发解决方案。 您正在从数据库中提取数据并尝试将结果放入UTF-8格式的平面文件(.CSV)中。解决方案完美地导出数据并保留文件中的特殊字符,因为您已使用65001作为代码页。

但是,当您打开文本文件或尝试将其加载到另一个进程时,它会说该文件是ANSI而不是UTF-8。如果您在记事本中打开文件并执行SAVE AS并将编码更改为UTF-8,然后您的外部流程可以正常工作,但这是一项繁琐的手动工作。

我发现当您指定Flat文件连接管理器的Code Page属性时,它会生成一个UTF-8文件。但是,它会生成一个UTF-8文件的版本,它错过了我们称之为字节顺序标记的内容。

因此,如果您的CSV文件包含字符AA,则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);

我希望这会有所帮助!!

答案 3 :(得分:0)

好的 - 似乎在SQL Server Forums找到了可接受的解决方法。基本上我必须创建两个UTF-8模板文件,使用文件任务将它们复制到我的目的地,然后确保我附加数据而不是覆盖。

答案 4 :(得分:0)

对于非常大的文件,@ Prashanthi的内存中解决方案将导致内存不足异常。这是我的实现,是here的代码的变体。

    public static void ConvertFileEncoding(String path, 
                                           Encoding sourceEncoding, Encoding destEncoding)
    {
        // If the source and destination encodings are the same, do nothting.
        if (sourceEncoding == destEncoding)
        {
            return;
        }

        // otherwise, move file to a temporary path before processing
        String tempPath = Path.GetDirectoryName(path) + "\\" + Guid.NewGuid().ToString() + ".csv";
        File.Move(path, tempPath);

        // Convert the file.
        try
        {
            FileStream fileStream = new FileStream(tempPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            using (StreamReader sr = new StreamReader(fileStream, sourceEncoding, false))
            {
                using (StreamWriter sw = new StreamWriter(path, false, destEncoding))
                {
                    //this seems to not work here
                    //byte[] utf8 = new byte[] { 0xef, 0xbb, 0xbf };
                    //sw.BaseStream.Write(utf8, 0, utf8.Length);

                    int charsRead;
                    char[] buffer = new char[128 * 1024];
                    while ((charsRead = sr.ReadBlock(buffer, 0, buffer.Length)) > 0)
                    {
                        sw.Write(buffer, 0, charsRead);
                    }
                }
            }
        }
        finally
        {
            File.Delete(tempPath);
        }
    }

答案 5 :(得分:0)

我知道这是一个非常古老的话题,但是这里有另一个答案,它可能比已经发布的其他答案更容易实现(请选择)。

  1. 我找到了this;您可以从this location下载.exe文件。 (免费)。
  2. 请务必按照第一个链接中的说明进行操作,并将.exe复制到C:\ Windows \ System32和C:\ Windows \ SysWOW64中,以方便使用,而不必键入/记住复杂的路径。
  3. 在SSIS中,添加一个执行过程任务。
  4. 在“进程”->“可执行文件”字段中使用convertcp.exe配置对象。
  5. 使用“进程->自变量”字段中的自变量配置对象,内容如下:0 65001 / b / i“ \ .csv” / o“ \ _UTF-8.csv “
  6. 我建议将“窗口样式”设置为隐藏。
  7. 完成!如果运行包,则执行过程任务将把原始ANSI文件转换为UTF-8。您也可以从其他代码页转换为其他代码页。只需找到代码页编号,您就可以开始使用!

基本上,此命令行实用工具使SSIS能够使用执行过程任务从代码页转换为代码页。对我来说就像一个魅力。 (当然,如果部署到SQL Server,则还必须将可执行文件复制到系统文件夹中的服务器中。)

最好,拉斐尔