有一个非常简单的SSIS包:
每次我运行这个包时,在Notepad ++中打开它的ANSI平面文件,而不是UTF-8。如果我检查Unicode选项,则该文件是UCS-2 Little Endian。
我做错了什么 - 如何让平面文件成为UTF-8编码?
由于
答案 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)
我知道这是一个非常古老的话题,但是这里有另一个答案,它可能比已经发布的其他答案更容易实现(请选择)。
基本上,此命令行实用工具使SSIS能够使用执行过程任务从代码页转换为代码页。对我来说就像一个魅力。 (当然,如果部署到SQL Server,则还必须将可执行文件复制到系统文件夹中的服务器中。)
最好,拉斐尔