原因:
SSIS无法读取文件,并显示以下警告,原因是列分隔符Ç
(带有锐音的“c”)而不是行分隔符{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 ++创建一个简单的平面文件,其中有几行。以下示例文件每行都有产品ID和列表价格信息,以Ç
作为列分隔符,并以{LF}
作为行结束符。
![Flat file source](https://istack.dev59.com/Jj1vC.webp)
在Notepad++中,单击
编码
,然后单击
以UTF-8编码保存
,将平面文件保存为
UTF-8
编码。
![Encoding UTF-8](https://istack.dev59.com/PLuts.webp)
示例将使用名为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
,并将变量设置为值
Ç
。
![Package variables](https://istack.dev59.com/HzZaW.webp)
右键单击连接管理器
,然后单击新建扁平文件连接...
以创建一个连接来读取扁平文件。
![Flat File Connection](https://istack.dev59.com/uRJsm.webp)
在
Flat File Connection Manager Editor的
General
页面上,执行以下操作:
- 将Connection manager name设置为
ProductListPrice
- 将Description设置为
Flat file connection manager to read product list price information.
- 选择平面文件路径。我有文件在路径
C:\Siva\StackOverflow\Files\6268205\ProductListPrice.txt
- 从Header Row Delimiter中选择
{LF}
- 勾选
Column names in the first data row
- 点击
Columns
页面
![Flat File Connection Manager Editor - General](https://istack.dev59.com/lGHr2.webp)
在
平面文件连接管理器编辑器的
列
页面上,确认
列分隔符
为空白并已禁用。点击
高级
页面。
![Flat File Connection Manager Editor - Columns](https://istack.dev59.com/y6qdg.webp)
在 Flat File 连接管理器编辑器 的 高级
页上,执行以下操作。
- 将 Name 设为
LineData
- 确认 Column delimiter 已设置为
{LF}
- 将 DataType 设为
Unicode string [DT_WSTR]
- 将 OutputColumnWidth 设为
255
- 单击
Preview
页。
![Flat File Connection Manager Editor - Advanced](https://istack.dev59.com/Fuc2I.webp)
在
Flat File Connection Manager Editor的
预览
页面上,验证显示的数据是否正确,并单击
确定
。
![Flat File Connection Manager Editor - Preview](https://istack.dev59.com/Uf4p8.webp)
您将在包的底部的连接管理器
选项卡上看到数据源Sora和平面文件连接管理器ProductListPrice。
![Connection Managers](https://istack.dev59.com/hR6kY.webp)
将Data Flow Task
拖放到包的Control Flow选项卡上,并将其命名为File to database - Without Cedilla delimiter
![Data Flow Task 1](https://istack.dev59.com/LVfWQ.webp)
双击“数据流任务”将视图切换到包上的“数据流”选项卡。在“数据流”选项卡上拖放“平面文件源”。双击“平面文件源”以打开“平面文件源编辑器”。
在“平面文件源编辑器”的“连接管理器”页面上,选择“平面文件连接管理器”“ProductListPrice”,然后单击“列”页面。
![Flat File Source Editor - Connection Manager](https://istack.dev59.com/M2DTm.webp)
在
平面文件源编辑器的
列
页面上,选中
LineData
列并点击
OK
。
![Flat File Source Editor - Columns](https://istack.dev59.com/44kzi.webp)
将一个
脚本组件
拖放到
Data Flow选项卡下的
Flat File Source之后,选择
转换
并单击
OK
。将绿色箭头从
Flat File Source连接到
Script Component。双击
Script Component以打开
Script Transformation Editor
。
在
Script Transformation Editor上单击
Input Columns,然后选择
LineData
列。单击
Inputs and Outputs页面。
![Script Transformation Editor - Input Columns](https://istack.dev59.com/OOjhK.webp)
在
脚本转换编辑器的
输入和输出
页面上,执行以下操作。
- 将输入名称更改为FlatFileInput。
- 将输出名称更改为
SplitDataOutput
。
- 选择输出列并单击
添加列
。再次重复此步骤以添加另一列。
- 将第一列命名为
ProductId
。
- 将列ProductId的数据类型设置为
Unicode字符串[DT_WSTR]
。
- 将长度设置为
30
。
![Script Transformation Editor - Inputs and Outputs - ProductId](https://istack.dev59.com/T7Bth.webp)
在
脚本转换编辑器的
输入和输出
页面执行以下操作:
- 将第二列命名为
ListPrice
- 将ListPrice列的DataType设置为
numeric [DT_NUMERIC]
- 将Precision设置为
12
- 将Scale设置为
2
- 单击Script页面以修改脚本
![Script Transformation Editor - Inputs and Outputs - ListPrice](https://istack.dev59.com/khpDA.webp)
在
脚本转换编辑器的
脚本
页面上,执行以下操作。
- 单击ReadOnlyVariables旁边的省略号按钮,然后选择变量
User::ColumnDelimiter
- 单击
编辑脚本...
![Script Transformation Editor - Script](https://istack.dev59.com/f9IBi.webp)
将以下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]);
}
}
![Script Component Code - C#](https://istack.dev59.com/Ncv02.webp)
将OLE DB Destination
拖放到Data Flow选项卡上。将Script Component的绿色箭头连接到OLE DB Destination。双击OLE DB Destination打开OLE DB Destination Editor
。
在OLE DB Destination Editor的Connection Manager
页面上,执行以下操作。
- 从OLE DB Connection Manager中选择
Sora
- 从Data access mode中选择
Table or view - fast load
- 从Name of the table or the view中选择
[dbo].[ProductListPrice]
- 点击Mappings页面
![OLE DB Destination Editor - Connection Manager](https://istack.dev59.com/NE6n0.webp)
点击OLE DB Destination Editor
上的Mappings
页面,如果输入和输出列名相同,则会自动映射列。 点击OK
。
![OLE DB Destination Editor - Mappings](https://istack.dev59.com/s2wUC.webp)
数据流选项卡在配置所有组件后应该看起来像这样。
![Data Flow tab](https://istack.dev59.com/Is6LJ.webp)
在SQL Server Management Studio (SSMS)中执行查询
select * from dbo.ProductListPrice
,以查找表中的行数。在执行包之前,它应该是空的。
![Rows in table before package execution](https://istack.dev59.com/xD9ni.webp)
执行该包。您会注意到该包成功处理了9行。该扁平文件包含10行,但第一行是带有列名称的标题。
![Package execution without delimiter](https://istack.dev59.com/Ca2eK.webp)
在SQL Server管理工具(SSMS)中执行查询
select * from dbo.ProductListPrice
,以查找成功插入表中的
9行。数据应与平面文件数据匹配。
![Rows in table after package execution](https://istack.dev59.com/cCoy0.webp)
上面的例子说明了如何使用
Script Component手动拆分数据,因为
Flat File Connection Manager在配置列分隔符
Ç
时会遇到错误。
问题模拟:
此示例显示了一个单独的Flat File Connection Manager,配置了列分隔符Ç
,它执行但遇到警告并且不处理任何行。
右键单击连接管理器
,然后单击新建平面文件连接...
以创建连接以读取平面文件。 在Flat File Connection Manager Editor的常规
页面上,执行以下操作:
- 将连接管理器名称设置为
ProductListPrice_Cedilla
- 将描述设置为
带有Cedilla列分隔符的平面文件连接管理器。
- 我有一个位于路径
C:\Siva\StackOverflow\Files\6268205\ProductListPrice.txt
的文件。选择平面文件路径。
- 从标题行分隔符中选择
{LF}
- 勾选
第一行数据中包含列名
- 单击
列
页面
![Flat File Connection Manager Editor - With Cedilla - General](https://istack.dev59.com/uORxZ.webp)
在
平面文件连接管理器编辑器的
列
页面上,执行以下操作:
- 将行分隔符设置为
{LF}
- 列分隔符字段可能已被禁用。单击
重置列
- 将列分隔符设置为
Ç
- 单击
高级
选项卡
![Flat File Connection Manager Editor - With Cedilla - Columns](https://istack.dev59.com/Dxxjz.webp)
在
平面文件连接管理器编辑器的
高级
页面上,执行以下操作:
- 将名称设置为
ProductId
- 将列分隔符设置为
Ç
- 将数据类型设置为
Unicode字符串[DT_WSTR]
- 将长度设置为
30
- 单击
ListPrice
列
![Flat File Connection Manager Editor - With Cedilla - Advanced - ProductId](https://istack.dev59.com/dIkQM.webp)
在
Flat File Connection Manager Editor的
高级
页面上,执行以下操作:
- 将Name设置为
ListPrice
- 将ColumnDelimiter设置为
{LF}
- 将DataType设置为
numeric [DT_NUMERIC]
- 将DataPrecision设置为
12
- 将DataScale设置为
2
- 点击
OK
![Flat File Connection Manager Editor - With Cedilla - Advanced - ListPrice](https://istack.dev59.com/FFejO.webp)
在“控制流”选项卡上拖放一个“数据流任务”,并将其命名为“文件到数据库 - 使用 Cedilla 分隔符”。禁用第一个数据流任务。
![Data Flow Task 2](https://istack.dev59.com/okNYs.webp)
使用Flat File Source
和OLE DB Destination
配置第二个数据流任务
![Data Flow Tab - 2](https://istack.dev59.com/EPRiF.webp)
双击平面文件源以打开平面文件源编辑器
。 在平面文件源编辑器的连接管理器
页面上,选择平面文件连接管理器ProductListPrice_Cedilla
,然后单击列页面以配置列。 单击确定
。
![Flat File Source Editor - Cedilla](https://istack.dev59.com/d5AN9.webp)
执行该包。所有组件将显示绿色以指示过程成功,但不会处理任何行。您可以看到在Flat File Source
和OLE DB Destination
之间没有行号指示。
![Package Execution - Cedilla](https://istack.dev59.com/yVPJz.webp)
点击 进度
选项卡,您将会看到以下警告信息。
[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.
![Progress Warning message](https://istack.dev59.com/Z2USN.webp)