使用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 辅助阅读博客
大家可以根据对应的视频课程名称查找相关的辅助阅读博客,有少量辅助阅读博客和视频课程讲解内容相同,大部分都是拓展总结部分.希望大家在学完每一个视频课程之后看看相关博客内容,这样可以在知识面和深度上继续得 ...
随机推荐
- android 破解工具
来记录一下本人在平时工作中使用的android上的破解工具 静态破解: apktool: apk包 -> dex dex2jar和enjarify(google官方出品): dex->ja ...
- QT打开ROS工作空间时遇到的问题和解决方法
之前一直觉得不用IDE写程序看着好像我很能的样子. 其实就相当于工业时代我还钻木取火并且告诉别人你们用打火机根本不知道火被点燃的过程是怎样的. 因为这个技能并非人人都会,就可以拿出去到处臭屁 好了, ...
- java开发前奏
做java开发当然少不了jdk(java开发工具),那么今天就介绍一下jdk的安装和配置. JDK官网下载地址(建议去官网下载,免费的) http://www.oracle.com/technetwo ...
- 练习使用XRecyclerView,可上拉下拉刷新。
package com.lixu.testxrecyclerview; import android.support.v7.app.AppCompatActivity; import android. ...
- movebase导航
利用turtlebot 的导航配置文件 由于movbase发的速度太不友好了所以使用了ros自带的滤波安装相应的包 apt-get install ros-indigo-yocs-velocity-s ...
- 快速分析apk工具aapt的使用
前面walfred已经介绍了使用apktool对apk进行逆向编译,通过apktool我们的确可以反编译已经序列化后的AndroidManifest.xml和资源文件等等,但是有没有一种快速有效的工具 ...
- Python排序算法
不觉已经有半年没写了,时间真是容易荒废,这半年过了个春节,去拉萨旅行.本职工作也很忙,没有开展系统的学习和总结. 今年开始静下心来从基础开始学习,主要分为三部分,算法.线性代数.概率统计. 首先学习算 ...
- redhat6.4上安装mysql
1.挂载操作系统介质 [root@server- ~]# mkdir -p /media/dvd [root@server- ~]# -20130130.0-Server-x86_64-DVD1.is ...
- stanford Protege 4.3 ERROR: Bundle org.protege.common 解决方法
我的java版本是jdk1.8.0_45,安装了protege后打开总显示: ERROR: Bundle org.protege.common [1] Error starting file:/hom ...
- Serv-U FTP之PASV和PORT模式
Serv-U 设置好后,访问,却提示如下错误:ftp服务器上的文件夹时发生错误,请检查是否有权限访问该文件夹.在解决此问题前,我亲自遇到该问题,看看我查的资料 FTP的连接一般是有两个连接的,一个是客 ...