为啥 SSIS 在导入 UTF-8 平面文件时无法识别换行符 LF 行分隔符?
Posted
技术标签:
【中文标题】为啥 SSIS 在导入 UTF-8 平面文件时无法识别换行符 LF 行分隔符?【英文标题】:Why doesn't SSIS recognize line feed LF row delimiter while importing UTF-8 flat file?为什么 SSIS 在导入 UTF-8 平面文件时无法识别换行符 LF 行分隔符? 【发布时间】:2011-09-10 05:24:13 【问题描述】:我正在尝试使用 SSIS 将数据从 utf-8 编码的平面文件导入 SQL Server 2008。这是 Notepad++ 中行数据末尾的样子:
我还有几张图片显示了文件连接管理器的外观:
您可以在文件连接管理器预览中看到数据正确显示。当我尝试导入这些数据时,没有行导入。我收到一条错误消息,指出未找到行分隔符。您可以在文件连接管理器图像中看到标题行分隔符和行分隔符都设置为LF
。这足以生成正确的预览,所以我不知道为什么它无法导入。我尝试了一些结果为零的事情:
[平面文件源 [582]] 警告: 到达数据文件的末尾,而 读取标题行。确保 标题行分隔符和数量 要跳过的标题行是正确的。
感谢您查看此内容,非常感谢您提供的任何帮助。
【问题讨论】:
【参考方案1】:原因:
由于列分隔符 Ç
("c" with cedilla)和 not
,SSIS 无法读取文件并显示以下警告 由于行分隔符 LF
(换行)。
[Read flat file [1]] Warning: The end of the data file was reached while
reading header rows. Make sure the header row delimiter and the number of
header rows to skip are correct.
这是一个示例 SSIS 包,展示了如何使用 Script Component
解决问题,最后还有另一个示例可以模拟您的问题。
分辨率:
下面的示例包是用SSIS 2008 R2
编写的。它读取带有行分隔符 LF
的平面文件作为单列值;然后使用Script Component
拆分数据,将信息插入SQL Server 2008 R2
数据库中的表中。
使用Notepad++ 创建一个包含几行的简单平面文件。下面的示例文件在每行上都有 Product Id 和 List Price 信息,以 Ç
作为列分隔符,每行以 结尾>LF
分隔符。
在 Notepad++ 上,单击 Encoding
,然后单击 Encoding in UTF-8
以 UTF-8
编码保存平面文件。
示例将使用名为 Sora
的 SQL Server 2008 R2
数据库。使用下面给定的脚本创建一个名为 dbo.ProductListPrice
的新表。 SSIS 会将平面文件数据插入此表中。
USE Sora;
GO
CREATE TABLE dbo.ProductListPrice
(
ProductId nvarchar(30) NOT NULL
, ListPrice numeric(12,2) NOT NULL
);
GO
使用 Business Intelligence Development Studio (BIDS) 2008 R2 创建一个 SSIS 包。将包命名为 SO_6268205.dtsx
。创建一个名为 Sora.ds
的数据源以连接到 SQL Server 2008 R2 中的数据库 Sora
。
右键单击包内的任意位置,然后单击 Variables
以查看变量窗格。在包作用域 SO_6268205
中创建一个名为 ColumnDelimiter
的数据类型为 String
的新变量,并将变量设置为 强>Ç
右键单击 Connection Managers
并单击 New Flat File Connection...
以创建连接以读取平面文件。
在平面文件连接管理器编辑器的General
页面上,执行以下操作:
ProductListPrice
将描述设置为Flat file connection manager to read product list price information.
选择平面文件路径。我在路径 C:\Siva\***\Files\6268205\ProductListPrice.txt
中有文件
从标题行分隔符中选择LF
检查Column names in the first data row
点击Columns
页面
在平面文件连接管理器编辑器的Columns
页面上,确认Column delimiter
为空白并被禁用。点击Advanced
页面。
在平面文件连接管理器编辑器的Advanced
页面上,执行以下操作。
LineData
确认列分隔符设置为LF
将DataType设置为Unicode string [DT_WSTR]
将OutputColumnWidth设置为255
点击Preview
页面。
在平面文件连接管理器编辑器的Preview
页面上,验证显示的数据是否正确,然后单击OK
.
您将在包底部的 Connection Managers
选项卡上看到数据源 Sora 和平面文件连接管理器 ProductListPrice .
将Data Flow Task
拖放到包的控制流选项卡上,并将其命名为File to database - Without Cedilla delimiter
双击 Data Flow Task 将视图切换到包上的 Data Flow
选项卡。将 Flat File Source
拖放到 数据流 选项卡上。双击平面文件源打开Flat File Source Editor
。
在平面文件源编辑器的Connection Manager
页面上,选择平面文件连接管理器ProductListPrice
并点击列页面。
在平面文件源编辑器的Columns
页面上,勾选LineData
栏并点击@987654410 @。
将Script Component
拖放到平面文件源下方的数据流选项卡上,选择Transformation
并单击 OK
。将 Flat File Source 的绿色箭头连接到 Script Component。双击脚本组件打开Script Transformation Editor
。
单击脚本转换编辑器上的输入列并选择LineData
列。点击输入和输出页面。
在脚本转换编辑器的Inputs and Outputs
页面上,执行以下操作。
SplitDataOutput
选择输出列并点击Add Column
。再次重复此操作以添加另一列。
命名第一列ProductId
将ProductId列的DataType设置为Unicode string [DT_WSTR]
将长度设置为30
在脚本转换编辑器的Inputs and Outputs
页面上,执行以下操作。
ListPrice
将ListPrice列的DataType设置为numeric [DT_NUMERIC]
将精度设置为12
将比例设置为2
点击脚本页面修改脚本
在脚本转换编辑器的Script
页面上,执行以下操作。
User::ColumnDelimiter
点击Edit Script...
在脚本编辑器中粘贴以下 C#。该脚本执行以下任务。
使用变量User::ColumnDelimiter中定义的列分隔符值Ç
,方法FlatFileInput_ProcessInputRow
分割传入的值并将其分配给脚本组件转换中定义的两个输出列。
C#中的脚本组件代码
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
public override void PreExecute()
base.PreExecute();
public override void PostExecute()
base.PostExecute();
public override void FlatFileInput_ProcessInputRow(FlatFileInputBuffer Row)
const int COL_PRODUCT = 0;
const int COL_PRICE = 1;
char delimiter = Convert.ToChar(this.Variables.ColumnDelimiter);
string[] lineData = Row.LineData.ToString().Split(delimiter);
Row.ProductId = String.IsNullOrEmpty(lineData[COL_PRODUCT])
? String.Empty
: lineData[COL_PRODUCT];
Row.ListPrice = String.IsNullOrEmpty(lineData[COL_PRICE])
? 0
: Convert.ToDecimal(lineData[COL_PRICE]);
将 OLE DB Destination
拖放到 数据流 选项卡上。将绿色箭头从 Script Component 连接到 OLE DB Destination。双击OLE DB Destination打开OLE DB Destination Editor
。
在OLE DB 目标编辑器的Connection Manager
页面上,执行以下操作。
Sora
从数据访问模式中选择Table or view - fast load
从表或视图的名称中选择[dbo].[ProductListPrice]
点击映射页面
如果输入和输出列名称相同,OLE DB 目标编辑器上单击Mappings
页面将自动映射列。点击OK
。
Data Flow 选项卡在配置完所有组件后应如下所示。
在SQL Server Management Studio (SSMS) 中执行查询select * from dbo.ProductListPrice
以查找表中的行数。在执行包之前它应该是空的。
执行包。您会注意到包成功处理了 9 行。平面文件包含 10 行,但第一行是带有列名的标题。
在 SQL Server Management Studio (SSMS) 中执行查询 select * from dbo.ProductListPrice
以查找成功插入到表中的 9 行。数据应与平面文件数据匹配。
以上示例说明了如何使用脚本组件手动拆分数据,因为平面文件连接管理器在配置列分隔符时遇到错误Ç
问题模拟:
此示例显示了一个单独的平面文件连接管理器,该管理器配置了列分隔符 Ç
,它执行但遇到警告并且不处理任何行。
右键单击 Connection Managers
并单击 New Flat File Connection...
以创建连接以读取平面文件。在平面文件连接管理器编辑器的General
页面上,执行以下操作:
ProductListPrice_Cedilla
将描述设置为Flat file connection manager with Cedilla column delimiter.
我在路径中有文件C:\Siva\***\Files\6268205\ProductListPrice.txt
选择平面文件路径。
从标题行分隔符中选择LF
检查Column names in the first data row
点击Columns
页面
在平面文件连接管理器编辑器的Columns
页面上,执行以下操作:
LF
列分隔符字段可能被禁用。点击Reset Columns
将列分隔符设置为Ç
点击Advanced
页面
在平面文件连接管理器编辑器的Advanced
页面上,执行以下操作:
ProductId
将ColumnDelimiter设置为Ç
将DataType设置为Unicode string [DT_WSTR]
将长度设置为30
点击栏目ListPrice
在平面文件连接管理器编辑器的Advanced
页面上,执行以下操作:
ListPrice
将ColumnDelimiter设置为LF
将DataType设置为numeric [DT_NUMERIC]
将DataPrecision设置为12
将DataScale设置为2
点击OK
将Data Flow task
拖放到控制流 选项卡上,并将其命名为File to database - With Cedilla delimiter
。禁用第一个数据流任务。
用Flat File Source
和OLE DB Destination
双击平面文件源打开Flat File Source Editor
。在平面文件源编辑器的Connection Manager
页面上,选择平面文件连接管理器ProductListPrice_Cedilla
并点击列 页面来配置列。点击OK
。
执行包。所有组件都将显示为绿色,表示处理成功,但不会处理任何行。可以看到 Flat File Source
和 OLE DB Destination
点击Progress
标签,您会看到以下警告信息。
[Read flat file [1]] Warning: The end of the data file was reached while
reading header rows. Make sure the header row delimiter and the number of
header rows to skip are correct.
【讨论】:
这是一个令人难以置信的答案。我无法表达我的感谢。这应该是 *** 的一个亮点示例。 谢谢你,再好不过了。【参考方案2】:上面的答案看起来非常复杂,只需转换文件中的行尾
Dim FileContents As String = My.Computer.FileSystem.ReadAllText("c:\Temp\UnixFile.csv")
Dim NewFileContents As String = FileContents.Replace(vbLf, vbCrLf)
My.Computer.FileSystem.WriteAllText("c:\temp\WindowsFile.csv", NewFileContents, False, New System.Text.UnicodeEncoding)
转自here
【讨论】:
不要将长篇文章与复杂性混淆。它可能看起来很复杂,但写得非常好,并出色地解释了该方法。相比之下,您的答案的质量要低得多,甚至不清楚它最初是如何回答问题的。请记住,这是 5 年前的问题【参考方案3】:如果您尝试通过 Windows 上的 SSIS 使用在 Unix、Mac 等不同平台上生成的 FlatFile,也会出现此问题
在这种情况下,您只需使用 unix2dos 命令将文件格式从 UNIX 转换为 DOS
unix2dos file-to-convert
【讨论】:
以上是关于为啥 SSIS 在导入 UTF-8 平面文件时无法识别换行符 LF 行分隔符?的主要内容,如果未能解决你的问题,请参考以下文章
使用SSIS从SQL Server 2005中的平面文件导入时如何保留NULL值
如何在 SSIS 中使用空格作为分隔符从平面文件中插入数据?