C# SSIS:如何在C中从管道分隔的平面文件中读取、通过匹配省略和写入记录#

C# SSIS:如何在C中从管道分隔的平面文件中读取、通过匹配省略和写入记录#,c#,sql-server,ssis,C#,Sql Server,Ssis,我是SSIS和C#编程的初学者,刚找到一份新工作,希望取得成功。我之前创建了一个包,用于将制表符分隔的平面文件转换为SQL Server表,但该平面文件是为转换而手动准备的。现在,我需要自动转换管道分隔文件,该文件像报表一样创建,并有多个标题行和子标题行。从管道到制表符分隔的转换对我来说不是问题。然而,我无法找到一种方法,也无法在网上获得任何帮助来理解如何读取每条记录、确定其内容以及省略或写入记录 我仅从Main()编写了下面显示的SSIS C#脚本,但我得到了以下错误,我不知道为什么会得到它。

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

我仅从
Main()
编写了下面显示的SSIS C#脚本,但我得到了以下错误,我不知道为什么会得到它。你能帮我吗

错误-(脚本任务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);
  }

打印文件路径的原因是,您正在使用保存文件路径的变量调用
StreamWriter.WriteLine()
,而不是使用文本本身。初始化
StreamWriter
时将使用文件路径,调用
WriteLine()
方法时将使用文本。我还建议将您不想写入的文本存储在字符串变量中,如下所示。如有必要,您可以添加将被过滤掉的其他字符串(即下面的“TextToOmit”字符串)。您可能需要对要省略的字符串进行一些修改,但下面的代码将保留在第一个标题上,并删除后续的字符串。您可以删除
Close()
方法,因为这是不必要的,因为在使用
块退出
时将关闭该方法。带有空格的行也会被
String.IndexOf
方法过滤掉,当找不到文本时,该方法返回-1。您提到了获得直接匹配的问题,您可以将
IndexOf
方法与
stringcomparison.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);
            }
        }
    }
}
string sourcePath=Dts.Variables[“User::Source_Path”].Value.ToString();
字符串destinationPath=Dts.Variables[“User::Destination_Path”].Value.ToString();
string line=string.Empty;
string outputText=string.Empty;
字符串headerText=“YourHeaderLine”;
string secondTextToOmit=“textthastneedstobe省略”;
字符串thirdTextToOmit=“textthastneedstobedeleted”;
int headerCount=0;
尝试
{
使用(StreamReader sr=新的StreamReader(sourcePath))
{
而((line=sr.ReadLine())!=null)
{
//只写第一次发生
如果(行==headerText&&headerCount==0)
{
outputText=outputText+line+Environment.NewLine;
headerCount++;
}
其他的
//将文本存储在变量中,以便在同一if语句中执行所有检查
//IndexOf查找while空间
if(line.IndexOf(“”)<0&&line!=headerText
&&行!=第二行文本输入(&line)=第三行文本输入)
{
outputText=outputText+line+Environment.NewLine;
}
//使用文件路径初始化StreamWriter
使用(StreamWriter writer=newstreamwriter(destinationPath))
{
//使用过滤文本写入字符串
writer.WriteLine(输出文本);
}
}
}
}
不区分大小写的匹配示例:

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

您确定代码正确吗?保存/关闭脚本任务时是否收到任何错误消息?您缺少
Main
method的结束括号您可以使用具有不同字段和行分隔符的平面文件源。你不需要转换任何东西。真正的问题似乎是如何忽略无效行。您可以将错误行为设置为“忽略”以忽略组页眉和页脚。您可以指定要跳过的标题行和数据行数。这在大多数情况下都有效,除了字段名称后面的组/页标题为什么要从管道转换为选项卡?我看不出有什么意义。我这样处理文件的方法是将整行导入到一列中,然后将该列拆分为多列。就我个人而言,我发现调试它要比在SSIS包中以交互方式调试C#任务容易得多。这是我自己的代码,因此可能有不正确的部分。这就是我需要确定的。亲爱的用户FL89,非常感谢您的建议和解释。你回答了我所有关于你为什么使用某些统计数据的问题