使用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 辅助阅读博客
大家可以根据对应的视频课程名称查找相关的辅助阅读博客,有少量辅助阅读博客和视频课程讲解内容相同,大部分都是拓展总结部分.希望大家在学完每一个视频课程之后看看相关博客内容,这样可以在知识面和深度上继续得 ...
随机推荐
- 20145224&20145238 《信息安全系统设计基础》 第一次实验
20145224&20145238 <信息安全系统设计基础>第一次实验 课程:信息安全系统设计基础 班级:1452 姓名:陈颢文 荆玉茗 学号:20145224 20145238 ...
- quartz-2.2.x 快速入门 (1)
欢迎来到quartz快速入门教程.阅读本教程,你将会了解: quartz下载 quartz安装 根据你的需要,配置Quartz 开始一个示例应用 当熟悉了quratz调度的基本功能后,可以尝试一些 ...
- 关于如何来构造一个String类
今天帮着一位大二的学弟写了一个String的类,后来一想这个技术点,也许不是什么难点,但是还是简单的记录一些吧! 为那些还在路上爬行的行者,剖析一些基本的实现..... 内容写的过于简单,没有涉及到其 ...
- Hibernate 测试分析 好多题都是没认真看题错了。
此题目考查的是对Hibernate中交叉连接的理解.HQL支持SQL风格的交叉连接查询,交叉连接适用于两个类之间没有定义任何关联时.在where字句中,通过属性作为筛选条件,如统计报表数据.使用交叉连 ...
- wifidog 配置中文说明
#网关IDGatewayID default#外部网卡ExternalInterface eth0#无线网卡GatewayInterface eth0#无线IPGatewayAddress 192.1 ...
- Rest接口测试,巧用firebug插件
两年前开始做软件测试,刚接触的是关于rest接口的测试.作为一个刚进职场的测试小菜鸟,当时对接口的理解并不是很充分,具体是怎么实现的也不清楚.在进行接口测试时,只是设置接口入参,调用接口,查看接口是否 ...
- python讲一个列表写入excel表中
连接为http://blog.csdn.net/a491057947/article/details/47614263 http://www.crifan.com/export_data_to_exc ...
- python 语法常用 lambda
Python中lambda表达式学习 http://blog.csdn.net/imzoer/article/details/8667176
- goldengate 12c 12.2 新特性(updated)
GoldenGate 12.2已经提供下载,增加了不少新特性 1. 异构配置加强不在需要sourceDefs和AssumeTargetDefs文件,在队列文件中已经包含metadata信息,比如tab ...
- SQL Server 2005 控制用户权限访问表
转自:http://www.cnblogs.com/gaizai/archive/2011/07/14/2106617.html 一.需求 在管理数据库过程中,我们经常需要控制某个用户访问数据库的权限 ...