使用 LINQ 验证文本文件






4.78/5 (5投票s)
本文将介绍如何基于 LINQ 验证文本文件。
引言
本文将介绍如何基于 LINQ 验证文本文件。
背景
一个平面文件正被用作数据文件来传递。为了使该文件被其他系统接受,该文件必须遵循其他系统期望的数据格式。不仅是数据格式,一些业务规则也可能需要在发送文件之前进行预评估。在本文中,我将构建一个基于 LINQ 的文本文件验证引擎,以挑战该文件是否满足我为一个系统处理它而定义的所有要求。
需要验证的规则
有效文件应具有 HEADER 记录、FOOTER 记录和一些 CONTENT 记录。前 3 个字符将用于描述记录的类型。在本例中,我将使用 111 表示 HEADER 记录,999 表示 FOOTER 记录,222 表示 CONTENT 记录。我们可以使用 4-6 个字符来描述子记录信息。但是,我将仅在此处演示 HEADER、FOOTER 和 CONTENT 记录。文件示例
111this is header record
222allen.y.w#gmail.com 123-45-6789
222allen.y.w4gmail.com 123456789
222allen.y.w@gmail.com 123-45-6789
999totalrecord5
在上面的文件中,以下是我要验证的一些基本规则
- 文件需要有一个 HEADER 记录,该记录具有固定长度 (16) --> 如果不满足,则引发错误消息。
- 文件需要有一个或多个 CONTENT 记录,该记录具有固定长度 (40) --> 如果不满足,则引发错误消息。
- CONTENT 记录中从第 4 到 23 位的位置用于电子邮件信息,并且需要遵循电子邮件格式 (xxx@xxx.xxx) --> 如果不满足,则引发警告。
- CONTENT 记录中从第 24 到 40 位的位置用于 SSN 信息,并且需要像这样:xxx-xx-xxxx (x 仅为数字) -> 如果不满足,则引发警告。
- 文件需要有一个 FOOTER 记录。--> 如果不满足,则引发错误消息。
验证引擎类
由于验证引擎需要验证多种文本文件格式,因此我将创建一个抽象类 (BaseValidator
) 来构建基本功能。一个子类 (File1Validator
) 将根据其自身的规则来实现这些方法。BaseValidator
中的一个事件处理程序将在发生错误时处理传递给客户端的信息。
验证引擎实现
BaseValidator
BaseValidator
是一个抽象类。它具有一个 Validate()
方法,该方法驱动所有验证过程。在本例中,当我们调用 Validate()
时,它将始终执行 ValidateHeader()
、ValidateContent()
和 ValidateFooter()
过程。可以从子类重写 Validate()
方法以实现更多过程。
public virtual void Validate()
{
ValidateHeader();
ValidateContent();
ValidateFooter();
}
protected abstract void ValidateHeader();
protected abstract void ValidateContent();
protected abstract void ValidateFooter();
BaseValidator
还在发生错误时创建一个事件。事件调用可以提供验证引擎和客户端之间的通信。
public event EventHandler<validatingeventargs> EventOccured;
protected virtual void OnEventOccured(ValidatingEventArgs e)
{
EventHandler<validatingeventargs> handler = EventOccured;
if (handler != null)
{
handler(this, e);
}
}
ValidatingEventArgs
是一个对象,其中包含验证程序处理规则时的所有错误信息。由于它是一个 EventArgs 对象,因此我们可以遵循 .NET EventArgs 设计直接从 .NET EventArgs
对象继承。
namespace askbargains.com.txtValidator.Validation
{
public class ValidatingEventArgs : EventArgs
{
public ValidatingEventArgs(string msg,
MessageType mType, RecordType rType)
{
this.Message = msg;
this.MessageType = mType;
this.RecordType = rType;
}
public string Message { get; set; }
public MessageType MessageType { get; set; }
public RecordType RecordType { get; set; }
}
}
File1Validator
File1Validator
是 BaseValidator
的一个子类。它将仅验证我上面定义的规则。可以创建更多子类来处理不同类型的文件格式。
从我们的 File1Validator
,我们希望调用我们的 BaseValidator Validate()
方法来驱动基本验证流程;我们还可以在 File1Validator
的 Validate()
中指定额外的验证过程。
namespace askbargains.com.txtValidator.Validation
{
public class File1Validator: BaseValidator
{
//constructor
public File1Validator(string fileLocation)
: base(fileLocation)
{
}
public override void Validate()
{
//triger the BaseValidator's Validate
base.Validate();
//adding more rules for record1 if needed
//ex: this.ValidateAdditionalRules();
}
}
}
File1Validator
还处理这些 BaseValidator
抽象方法的实现。在本例中,这将是 ValidateHeader()
、ValidateContent()
和 ValidateFooter()
。
在我们的 File1Validator
中,我们还使用 LINQ 来查询文本文件中的每种类型的记录,并使用正则表达式来处理格式。业务规则也可以以相同的方式完成。
protected override void ValidateHeader()
{
//Select hearder rec from the file
var heaRec = from str in RecStrs
where str.Substring(0, 3) == Convert.ToString((int)RecordType.HEADER)
select str;
//add all the rules for header
if (heaRec.Count() == 0)
{
base.OnEventOccured(new ValidatingEventArgs("File DOES NOT " +
"contain Header record", MessageType.Error, RecordType.HEADER));
}
if (heaRec.Count() > 1)
{
base.OnEventOccured(new ValidatingEventArgs("Only one Header " +
"record allowed", MessageType.Error, RecordType.HEADER));
}
if (heaRec.Count() == 1)
{
if (heaRec.First().Length != 16)
{
base.OnEventOccured(new ValidatingEventArgs("Header record has " +
"to be 16 charcter", MessageType.Error, RecordType.HEADER));
}
//add more rules for header
}
}
protected override void ValidateContent()
{
//select content recs
var conRec = from str in RecStrs
where str.Substring(0, 3) == Convert.ToString((int)RecordType.CONTENT)
select str;
//add all the rules for content
if (conRec.Count() == 0)
{
OnEventOccured(new ValidatingEventArgs("File DOES NOT contain content record",
MessageType.Error, RecordType.CONTENT));
}
int counter = 0;
if (conRec.Count() > 0)
{
foreach (string address in conRec)
{
counter++;
if (address.Length != 40)
{
OnEventOccured(new ValidatingEventArgs("Content record has to be 40",
MessageType.Error, RecordType.CONTENT));
}
else
{
if (!email.IsMatch(address.Substring(3, 20)))
{
OnEventOccured(new ValidatingEventArgs("Email is invliad " +
"for content " + counter.ToString(),
MessageType.Warning, RecordType.CONTENT));
}
if (!ssn.IsMatch(address.Substring(23, 11)))
{
OnEventOccured(new ValidatingEventArgs("SSN is invliad " +
"fro content" + counter.ToString(),
MessageType.Warning, RecordType.CONTENT));
}
}
}
}
}
protected override void ValidateFooter()
{
//check if file has Footer rec
var fooRec = RecStrs
.Where(rec => (rec.Substring(0, 3) ==
Convert.ToString((int)RecordType.FOOTER)))
.Select(rec => rec.Substring(0, 3));
if (fooRec.Count() == 0)
{
OnEventOccured(new ValidatingEventArgs("File DOES NOT contain Footer Record",
MessageType.Warning, RecordType.FOOTER));
}
}
客户端处理错误消息
在本示例中,我使用一个窗口应用程序来表示来自 File1Validator
的错误信息。由于每当捕获到错误时都会引发 ErrorOccured
事件,因此 Windows UI 将委托 EventOccured
并打印错误详细信息。
查看当我们从 UI 单击 StartValidate
时的代码
private void btnStart_Click(object sender, EventArgs e)
{
this.listView1.Items.Clear();
try
{
File1Validator recValidator = new File1Validator(textBox1.Text);
recValidator.EventOccured +=
new EventHandler<validatingeventargs>(recValidator_EventOccured);
recValidator.Validate();
MessageBox.Show("Validation completed");
}
catch (NullReferenceException ex)
{
MessageBox.Show("select an filepath", ex.Message);
}
}
void recValidator_EventOccured(object sender, ValidatingEventArgs e)
{
//handle error msg
if (e.MessageType == MessageType.Error)
{
listView1.Items.Add(new ListViewItem(new string[] { e.MessageType.ToString(),
sender.ToString().Substring(sender.ToString().LastIndexOf(".") + 1),
e.RecordType.ToString(), e.Message }, "error.jpeg"));
}
//handle warning msg
else if (e.MessageType == MessageType.Warning)
{
listView1.Items.Add(new ListViewItem(new string[] { e.MessageType.ToString(),
sender.ToString().Substring(sender.ToString().LastIndexOf(".") + 1),
e.RecordType.ToString(), e.Message }, "warning.jpeg"));
}
}
Validator_EventOccured
将处理 ValidatingEventArgs
对象并在 UI 窗口中显示结果。
结论
在此应用程序中,我们构建了一个验证引擎来评估一个文本文件,以处理每一行并在不满足要求时生成错误。