【问题标题】:SSIS - Flat file always ANSI never UTF-8 encodedSSIS - 平面文件总是 ANSI 从不 UTF-8 编码
【发布时间】:2011-07-16 09:51:22
【问题描述】:

有一个非常直接的 SSIS 包:

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

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

我做错了什么 - 我怎样才能让平面文件进行 UTF-8 编码?

谢谢

【问题讨论】:

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

标签: utf-8 ssis flat-file


【解决方案1】:

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

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

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

最好的,拉斐尔

【讨论】:

    【解决方案2】:

    对于非常大的文件,@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);
            }
        }
    

    【讨论】:

      【解决方案3】:

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

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

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

      我发现,当您指定平面文件连接管理器的代码页属性时,它会生成一个 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);
      

      希望对你有帮助!!

      【讨论】:

      • 我正在做一个项目,我将把 CSV 文件交给一个 Linux 团队,该团队最终会将它们加载到 MySQL 仓库中。你的方法是唯一对他们有用的方法。您的代码有效,我只添加了参数化。任何创建 UTF-8 编码文件的尝试均未成功。
      • 5 年后,我们开始遇到上述实现的内存不足异常。我不得不用基于流的解决方案来替换它,该解决方案以块的形式处理文件。我将在单独的答案中发布。
      【解决方案4】:

      为答案添加解释...

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

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

      文件追加解决方案是解决此问题的一种方法 - 通过使用正确的 BOM 创建一个空白文件,然后从 SSIS 追加数据,BOM 标题保持在原位。如果您告诉 SSIS 覆盖该文件,它也会丢失 BOM。

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

      【讨论】:

      • 我认为他们现在有 BOM 选项
      【解决方案5】:

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

      然后是 Source->Advance Editor -> Input 和 OutPut 属性 检查 External Columns 和 OutPut Columns 中的每一列,并尽可能将 CodePage 设置为 65001。

      就是这样。

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

      【讨论】:

      • 在源代码 -> 高级编辑器 -> 组件属性 -> 将默认代码页设置为 65001 AlwaysUseDefaultCodePage 为 True,此步骤帮助我节省了寻找双重代码页引用错误的时间
      • 请注意,这不适用于 NVARCHAR(MAX) 列,但如果您的查询转换为 NVARCHAR(4000),它确实有效。如果您的查询需要在一个字段中超过 4000 个字符,请尝试使用脚本组件或其他解决方案之一。
      【解决方案6】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-07
        • 1970-01-01
        • 1970-01-01
        • 2011-11-20
        • 1970-01-01
        • 2020-05-07
        • 2014-02-17
        相关资源
        最近更新 更多