使用Script Component源处理不规则平面文件
微软 BI 系列随笔 - SSIS 2012 高级应用 - Script Component处理不规则平面文件
场景介绍
在使用SSIS从平面文件导入源数据时,最常遇到的是以下两种情况:
- 导入规则的平面文件,这种文件的每一行数据的解析规则都是一样的
- 导入不规则的平面文件,这种文件可能包含多种数据结构,比如某些行是头(Head),某些行是内容(Content),某些行是尾(Tail),三种数据的解析格式都不一样
- 源文件的字符编码集不一样,例如文件是来自于不同的系统(或区域),这些文件的编码有可能是ANSI,Unicode或者UTF-8中的任何一种。
对于第一种情况,可以使用平面文件连接器(FlatFile Connection)来解析,通过配置他的字符集,格式,分隔符等就能做到。
对于第二种情况,要是使用平面文件连接器(FlatFile Connection)的话,需要使用临时文件,即使用平面文件连接器从源文件中中将每一行的数据读为一个类型,然后根据内容使用条件分离(Conditional Split)将内容分离,重新组织新的文件。然后正对新生成的文件做常规处理实现数据导入。
对于第三种情况,比较复杂,目前是不能使用平面文件连接器来解析的。平面文件连接器虽然支持表达式设置CodePage和是否是Unicode,以及其他的设置,但是具体操作起来比较麻烦。设计时有严重的干扰,经常常常导致编译不通过。
本文将针对第二种情况和第三种情况给读者一个思路,即使用Script Component作为数据源解析文件,输出数据,同时结合处理第二种情况。
实施步骤
分析平面文件格式
假设我们有如下格式的平面文件:
首先这个文件的编码是不规则的,他含有西班牙文(还有其他的文件,是不含这个文字集的)。
第二,他有02H和02D两种内容格式,姑且认为是Header和Detail。
所以说这种类型的文件使用平面文件连接器根本无法解析。
那么我们怎么办呢?看下面。
Script Component源
定义输入与输出
SSIS中支持使用Script Component作为数据源,你可以使用C#或者VB代码去做任何事情,然后将构造一个或多个数据集作为输出。如下所示:
本例中我定义了一个EDCOrder的输出用来放Header的内容,OrderDetail的内容我不需要所以没有定义。
我另外定义了一个FailedRows来放Header解析失败的的内容。没有输入。
编写脚本
在脚本页选择要使用的变量和脚本语言。
点击编辑脚本(Edit Script...)
这时候会打开一个Vsta project的脚本编辑项目。
这个项目包含三个文件
- ComponentWrapper.cs - 包含变量类,连接类和用户控件类
- BufferWrapper.cs - 定义了输出类
- main.cs - 脚本文件的入口函数,继承自用户控件类。
main.cs这个文件有三个方法
- PreExecute - 执行之前
- PostExecute - 执行之后
- CreateNewOutputRows 创建输出行
为了解析平面文件,我们定义了如下参数,主要是一个StreamReader来读文件,时间记录和行号:
System.IO.StreamReader sr;
DateTime now;
int rowNumber,failedRows;
Guid fileId;
string ContentLengthError;
string CoposIdNullError;
string errorMsg;
在PreExecute中这么写,根据传进来的文件名打开文件,定义错误消息,初始化变量
/// <summary>
/// This method is called once, before rows begin to be processed in the data flow.
///
/// You can remove this method if you don't need to do anything here.
/// </summary>
public override void PreExecute()
{
base.PreExecute(); now = DateTime.Now;
rowNumber = ;
failedRows = ;
fileId = Guid.Parse(Variables.pvFileID.ToString());
ContentLengthError = "Line content validation failed. Line content length is not equal to 1141.";
CoposIdNullError = "Line content validation failed. Copos id is required.";
errorMsg = "Filename: " + Variables.pvLoadFile + System.Environment.NewLine;
sr = new System.IO.StreamReader(Variables.pvLoadFile);
}
在PostExecute中这么写,关闭文件,返回错误信息给脚本调用的变量
/// <summary>
/// This method is called after all the rows have passed through this component.
///
/// You can delete this method if you don't need to do anything here.
/// </summary>
public override void PostExecute()
{
base.PostExecute(); sr.Close();
Variables.pvFailedRows = failedRows;
if (errorMsg != "Filename: " + Variables.pvLoadFile + System.Environment.NewLine)
Variables.pvErrorMessage += System.Environment.NewLine + errorMsg;
}
在CreateNewOutputRows这么写,根据每一行的内容判断消息类型,验证消息内容,生成输出行。
public override void CreateNewOutputRows()
{
/*
Add rows by calling the AddRow method on the member variable named "<Output Name>Buffer".
For example, call MyOutputBuffer.AddRow() if your output was named "MyOutput".
*/
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
if (line.StartsWith("02H"))
{
if (line.Length != )
{
FailedRowsBuffer.AddRow();
FailedRowsBuffer.RowNumber = rowNumber;
FailedRowsBuffer.ErrorDescription = ContentLengthError;
FailedRowsBuffer.Content = line;
failedRows++;
errorMsg += "At Row: " + rowNumber.ToString() + System.Environment.NewLine + "Error Description: " + ContentLengthError + System.Environment.NewLine;
}
else
{
if (!string.IsNullOrEmpty(line.Substring(, )) && !string.IsNullOrWhiteSpace(line.Substring(, ))) //Coposid is required
{
EDCOrderBuffer.AddRow();
EDCOrderBuffer.Coposid = line.Substring(, );
EDCOrderBuffer.Custname = line.Substring(, );
EDCOrderBuffer.Custtel = line.Substring(, );
EDCOrderBuffer.Dlvytitle = line.Substring(, );
EDCOrderBuffer.Dlvyinitial = line.Substring(, );
EDCOrderBuffer.Dlvyname = line.Substring(, );
EDCOrderBuffer.Dlvyhouse = line.Substring(, );
EDCOrderBuffer.Dlvytel = line.Substring(, );
EDCOrderBuffer.Dsptchsrvc = line.Substring(, );
EDCOrderBuffer.Dlvydate = line.Substring(, );
EDCOrderBuffer.Dmworder = line.Substring(, );
EDCOrderBuffer.Dsptchemail = line.Substring(, );
EDCOrderBuffer.OrderDate = line.Substring(, );
EDCOrderBuffer.FileId = fileId;
EDCOrderBuffer.CreatedOn = now;
}
else
{
FailedRowsBuffer.AddRow();
FailedRowsBuffer.RowNumber = rowNumber;
FailedRowsBuffer.ErrorDescription = CoposIdNullError;
FailedRowsBuffer.Content = line;
failedRows++;
errorMsg += "At Row: " + rowNumber.ToString() + System.Environment.NewLine + "Error Description: " + CoposIdNullError + System.Environment.NewLine;
}
}
}
rowNumber++;
}
}
编译下下这个Vsta项目。
处理Script Component输出
这样,一个不规则的文件就被我们使用Script Component轻松的处理了。
- 由于使用StreamReader,使用默认编码格式他会自动识别文件编码,避免了使用平面文件解析器出现乱码的情况
- 由于针对文件内容分别处理,可以解析不规则文件,产生多个输出
- 由于加入了自定义验证信息,可以验证消息的内容
疑问:
- 使用Script Component能否平行执行,EDCOrderBuffer.AddRow()的时候是不是就已经产生了一行输出了呢?这个有待研究
- 要写代码解析文件,有没有可以长度类型都是可以配置的,如果需要格式转换是否方便,或者在外部再做转换呢?
将这些问题留给读者朋友们去思考吧。
也可以给我留言大家一起讨论哦。
使用Script Component源处理不规则平面文件的更多相关文章
- 微软BI 之SSIS 系列 - 使用 Script Component Destination 和 ADO.NET 解析不规则文件并插入数据
开篇介绍 这一篇文章是 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧 的续篇,在上篇文章中介绍到了对于这种不规则文件输出的处理方式.比如下图中 ...
- 微软BI 之SSIS 系列 - 通过 ROW_NUMBER 或 Script Component 为数据流输出添加行号的方法
开篇介绍 上午在天善回答看到这个问题 - SSIS 导出数据文件,能否在第一列增加一个行号,很快就帮助解决了,方法就是在 SQL 查询的时候加一个 ROW_NUMBER() 就可以了. 后来想起在两年 ...
- Script component 用法
在SSIS中,可以使用C#编写脚本,这是十分激动人心的事,能够使用C#代码,使得Script Component无所不能. 第一部分:组件简介Script Component 有三种类型:Source ...
- Data Flow ->> Script Component
和Control Flow中的Script Task非常类似,不同的是Script Component是Per-Row的执行类型.打个比方,在Script Component中加入两个Output的字 ...
- Script Component 引用package variable
ScriptComponet 的变量分为两种类型,ReadOnly和ReadWrite,使用C#引用这两种类型的变量,有一点不同. 1,创建两个变量 2,将变量传递给script component ...
- Unity3d 拖拽脚本报错Can't add the script component "" because the script class cannot be found
解决办法: ①报错原因:文件名与文件内容中的类名不相符. ②关闭360.鲁大师等防护软件,重新安装系统.
- 微软BI SSIS 2012 ETL 控件与案例精讲面试 200 问(SSIS 面试题,ETL 面试题)
开篇介绍 本自测与面试题出自 微软BI SSIS 2012 ETL 控件与案例精讲 (http://www.hellobi.com/course/21) 课程,对于学完本课程的每一课时和阅读完相关辅助 ...
- 微软BI SSIS 2012 ETL 控件与案例精讲课程学习方式与面试准备详解
开篇介绍 微软BI SSIS 2012 ETL 控件与案例精讲 (http://www.hellobi.com/course/21) 课程从2014年9月开始准备,到2014年12月在 天善BI学院 ...
- 微软BI SSIS 2012 辅助阅读博客
大家可以根据对应的视频课程名称查找相关的辅助阅读博客,有少量辅助阅读博客和视频课程讲解内容相同,大部分都是拓展总结部分.希望大家在学完每一个视频课程之后看看相关博客内容,这样可以在知识面和深度上继续得 ...
随机推荐
- 0040 Linux 系统管理命令
1. 主机名称 hostname hostnamectl 2.开机启动 chkconfig systemctl 3.服务管理 service 服务名 start service 服务名 stop ...
- Excel 2013中单元格添加下拉列表的方法
使用Excel录入数据的时候我们通常使用下拉列表来限定输入的数据,这样录入数据就很少发生错误了.Excel 2013较以前的版本发生了很大的变化,那么在Excel 2013是如何添加下拉列表的呢? 下 ...
- uva 1658(最小费用最大流)
题意:一个带权有向图,求起点到终点的两条路径权值之和最小,且两条路径没有公共点(除起点,终点): 分析:拆点法,将u拆成u和u',u-u'容量为1,费用为0,这样就能保证每个点只用一次,起点s-s'容 ...
- mac xcworkspace xcodebuild
xcodebuild 在介绍xcodebuild之前,需要先弄清楚一些在XCode环境下的一些概念[4]: Workspace:简单来说,Workspace就是一个容器,在该容器中可以存放多个你创建的 ...
- plist
<a title="iphone" href="itms-services://?action=download-manifest&url=https:// ...
- 生成XML文件
import java.io.FileOutputStream;import java.io.IOException; import org.jdom.Document;import org.jdom ...
- Java mysql 日期相关
获取当前系统时间和日期并格式化输出: import java.util.Date;import java.text.SimpleDateFormat; public class NowString { ...
- 64位 ubuntu android studio gradle 权限不够 缺少文件和权限导致
安装 32位 库文件 sudo apt-get install lib32z1 给文件夹加权限 chmod 777 -R SDK chmod 777 -R android-studio -R表示所有 ...
- Python学习路程day10
Twsited异步网络框架 Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议.线程.数据库管理.网络操作.电子邮件等. 事件驱动 简而言之,事件驱动分为二个部分:第一,注册事 ...
- wndows程序设计之书籍知识与代码摘录-封装一个类似printf的messagebox
//----------------------------------------- //本程序展示了如何实现MessageBoxPrintf函数 //本函数能像printf那样格式化输出 //摘录 ...