使用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 辅助阅读博客
大家可以根据对应的视频课程名称查找相关的辅助阅读博客,有少量辅助阅读博客和视频课程讲解内容相同,大部分都是拓展总结部分.希望大家在学完每一个视频课程之后看看相关博客内容,这样可以在知识面和深度上继续得 ...
随机推荐
- JavaScipt 源码解析 css选择器
css1-css3提供了很多选择器,总得来说分为几大类: 群组选择器:逗号"," 简单选择器:ID,标签,类,属性,通配符 关系选择器:孩子,后代,兄弟,相邻 伪类选择器:动作伪类 ...
- iOS开发拓展篇—音频处理(音乐播放器2)
iOS开发拓展篇—音频处理(音乐播放器2) 说明:该文主要介绍音乐播放界面的搭建. 一.跳转 1.跳转到音乐播放界面的方法选择 (1)使用模态跳转(又分为手动的和自动的) (2)使用xib并设置跳转 ...
- android单选框和复选框(练习)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- Spring 整合 Hibernate
Spring 整合 Hibernate •Spring 支持大多数流行的 ORM 框架, 包括 Hibernate JDO, TopLink, Ibatis 和 JPA. •Spring 对这些 OR ...
- 收集Github上的iOS控件和开发资料
文章来源:http://www.mobile-open.com/2015/85017.html 动画 awesome-ios-animation 收集了iOS平台下比较主流炫酷的几款动画框架 RCTR ...
- enmo_day_03
安装 装载点 : /u01 (第一个挂载点 LUN1) /u01 (第二个挂载点LUN2) /disk01 目录 : /u01/app/oracle /u01/app/app 文件 : 控制文件 :c ...
- SQL 解决in的参数烦恼(经典,简洁,高效)
原SQL是不能执行的:select * from 表A where 字段A in (select 逗号分隔的字段B from 表B where 条件) 解决方案:select b.* from (se ...
- How To Use Hbase Bulk Loading
最近在学习hbase,学到利用如何将数据导入到hbase中,采用的方式是批量导入:bulk load的方法,中间出现了一些问题,下面将执行的步骤记录一下,以供日后查阅: 说明:导入的方式是将csv文件 ...
- 二叉搜索树 C++代码实现
暂未发现什么bug,如果发现请指出. #include<iostream> using namespace std; //定义二叉搜索树的结点 struct Node { int data ...
- Newtonsoft.Json(C#处理json)
转载自:http://blog.csdn.net/wswqiang/article/details/6783161 using Newtonsoft.Json; using System.Text; ...