SSIS:如何在C#中从管道定界的平面文件中读取,省略匹配并写入记录

时间:2018-12-03 11:14:00

标签: c# sql-server ssis

我是SSIS和C#编程的初学者,刚刚找到一份新工作,并且想打个分数。我之前创建了一个程序包,用于将制表符分隔的平面文件转换为SQL Server表,但是该平面文件是为转换而手动准备的。现在,我需要自动进行管道定界文件的转换,该文件的创建类似于报告,并且具有多个标题行和子标题行。从管道到制表符分隔的转换对我来说不是问题。但是,我只是找不到一种方法,也无法在线获得任何帮助来了解如何读取每条记录,确定其内容以及省略或写入记录。

我将下面显示的以下SSIS C#脚本仅从Main ()进行编码,但是出现了以下错误,并且我不知道为什么得到它。你能帮我吗?

  

错误-(脚本任务1的错误:找不到脚本的二进制代码。请通过单击“编辑脚本”按钮在设计器中打开脚本,并确保脚本成功构建。脚本任务1的错误:任务验证。)

该脚本应该:

1)读取管道分隔平面文件中的每个记录

2)检查每行/记录以确定它们是否包含以下值,如果它们包含以下值,则不写记录:

•空格

•价值-“业务部门:”等

•值-“员工ID |员工名称|部门ID |部门| EE家庭电话|紧急联系人姓名|主要|电话|关系”

•最后一个值是标题。我想写这个标题的第一个匹配项,但此后不要再写其他任何匹配的项。

脚本:

public void Main()
{
  string SourcePath = Dts.Variables["User::Source_Path"].Value.ToString();
  string DestinationPath = Dts.Variables["User::Destination_Path"].Value.ToString();
  string Line = string.Empty;

  try
  {
    using (StreamReader sr = new StreamReader(SourcePath))
    using (StreamWriter ds = new StreamWriter(DestinationPath))
    {
      while ((Line = sr.ReadLine()) != null)
      { 
        // MessageBox.Show(Line);
        if (Line == " ")
          Console.WriteLine("Blank Line");
        else
          if (Line == "Business Unit: 069 - DEPT OF XXXX XXXXX")
            Console.WriteLine("069 Heading");
          else
            if (Line == "Business Unit: 071 - DEPT. OF YYYYY YYYYYYY")
              Console.WriteLine("071 Heading");
            else
              if (Line == "Empl Id | Employee Name | Dept Id | Department | EE Home Phone | Emergency Contact Name | Primary | Telephone | Relationship")
                Console.WriteLine("Main Heading");

        // write to destination file
        ds.WriteLine(Dts.Variables["User::Destination_Path"].Value);
      }
      // close the stream
      ds.Close();
      //string data = sr.ReadToEnd();
      //MessageBox.Show(data);
    }
    Dts.TaskResult = (int)ScriptResults.Success;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK);
  }

1 个答案:

答案 0 :(得分:0)

打印文件路径的原因是因为您使用保存文件路径的变量调用StreamWriter.WriteLine(),而不是使用文本本身。初始化StreamWriter时将使用文件路径,而调用WriteLine()方法时将使用文本。我还建议按照以下步骤将您不想编写的文本存储在字符串变量中。如有必要,您可以添加其他将被过滤掉的字符串(即下面的“ TextToOmit”字符串)。您可能需要对要忽略的确切字符串进行几处修改,但是下面的代码将保留在第一个标头上,并删除后续的字符串。您可以删除Close()方法,因为它是不必要的,因为该方法将在退出using块时关闭。 String.IndexOf方法也过滤掉带有空格的行,当找不到文本时,该方法返回-1。您提到了有关获得直接匹配的问题,可以将IndexOf方法与StringComparision.CurrentCultureIgnoreCase参数一起使用来匹配第一个匹配项,而不区分大小写。但是,使用这种方法时,您将要确保要忽略的文本不会出现在任何需要保留的记录中,下面的示例在初始代码段中。我假设您想将每条记录写在新行上,这就是为什么在构建输出文本时添加Environment.NewLine属性的原因。

string sourcePath = Dts.Variables["User::Source_Path"].Value.ToString();
string destinationPath = Dts.Variables["User::Destination_Path"].Value.ToString();
string line = string.Empty;
string outputText = string.Empty;
string headerText = "YourHeaderLine";
string secondTextToOmit = "TextThatNeedsToBeOmitted";
string thirdTextToOmit = "TextThatNeedsToBeOmitted";
int headerCount = 0;
try
{
    using (StreamReader sr = new StreamReader(sourcePath))
    {
        while ((line = sr.ReadLine()) != null)
        {
            //only write first occurance
            if (line == headerText && headerCount == 0)
            {
                outputText = outputText + line + Environment.NewLine;
                headerCount++;
            }
            else
             //store text in variables to do checks all in same if statement
             //IndexOf looks for while space
             if (line.IndexOf(' ') < 0 && line != headerText
                && line != secondTextToOmit && line != thirdTextToOmit)
            {
                outputText = outputText + line + Environment.NewLine;
            }
            //initialize StreamWriter using file path
            using (StreamWriter writer = new StreamWriter(destinationPath))
            {
                //write the string using filtered text
                writer.WriteLine(outputText);
            }
        }
    }
}

不区分大小写的匹配示例:

line.IndexOf(thirdTextToOmit, 0, StringComparison.CurrentCultureIgnoreCase) < 0