SSIS 将 LF 设置为 CRLF 时将其读取为终止符

SSIS reading LF as terminator when its set as CRLF

使用 SSIS 2012。我的平面文件连接管理器我有一个带分隔符的文件,其中行分隔符设置为 CRLF,但是当它处理该文件时,我有一个文本列 LF 在里面。这导致它将其读取为导致它失败的行终止符。有什么想法吗?

在回答之前,我不认为该列仅包含 LF 因为如果行分隔符是 CRLF 它不会将其视为分隔符。所以它可能是 CRLF,但我会针对这两种情况(CRLF 或 LF)给出解决方案

解决方案

您可以通过以下步骤解决此问题:

  1. 首先在平面文件连接管理器中仅添加一列(类型 DT_STR 和长度 4000),因此您会将每一行视为一列。
  2. 在数据流任务中,您必须添加一个修复文件结构的脚本组件。并将行拆分为列。

简单测试

我会考虑一个包含以下内容的平面文件

ID;name;DOB;Notes;ClassID{CRLF}
1;John;2001-01-01;;1{CRLF}
2;Moh;2002-01-01;Very cool{LF}
Genius;2{CRLF}
3;Ali;2000-01-01;Calm;2{CRLF}
  1. 首先,我将使用以下选项添加平面文件连接管理器:
    • 行分隔符 = {CRLF}
    • Header 行分隔符 = {CRLF}

  1. 在 DataFlow 任务中,我将添加一个 Flat File Source、2 x Script ComponentOLEDB Destination

  2. 在第一个脚本组件中,我将标记 Column0 作为输入,我将添加 5 个输出列 ID,Name,DOB,Notes,ClassID,并将输出同步输入设置为 None

  1. 在第一个脚本组件中,我将编写一个脚本,将每一行存储在内存变量中,并在行完成且存在另一行时将其分配给输出行。

    Dim strLine As String = String.Empty
    
    Dim strDelimiter As String = ";"
    
    Public Sub EmptyMemoryVariables()
    
    
        strLine = String.Empty
    
    
    End Sub
    
    Public Sub AssignMemoryVariablesToOutput()
    
        With Output0Buffer
    
            .AddRow()
            .NewRow = strLine
        End With
    
    End Sub
    
    Public Function AreVariablesEmpty() As Boolean
    
        If strLine = "" Then
    
            Return True
    
        Else
    
            Return False
    
        End If
    
    
    End Function
    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
    
        Dim strColumns As String() = Row.Column0.Split(CChar(strDelimiter))
    
        If strColumns.Length = 5 Then
    
            If Not AreVariablesEmpty() Then
                AssignMemoryVariablesToOutput()
                EmptyMemoryVariables()
            End If
    
            strLine = Row.Column0
    
            AssignMemoryVariablesToOutput()
            EmptyMemoryVariables()
    
    
        Else
    
            If strLine.Split(CChar(strDelimiter)).Length = 5 Then
    
                AssignMemoryVariablesToOutput()
                EmptyMemoryVariables()
    
            End If
    
    
            strLine &= Row.Column0
    
    
    
    
    
    
    
        End If
    
  2. 在第二个脚本组件中,我会将每一行拆分为列

    Dim strDelimiter As String = ";"
    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)

        Dim strColumns As String() = Row.NewRow.Split(CChar(strDelimiter))


        Row.ID = strColumns(0)
        Row.NAME = strColumns(1)
        Row.DOB = strColumns(2)
        Row.NOTES = strColumns(3)
        Row.CLASSID = strColumns(4)


    End Sub

重要说明:提供的代码不是最佳的,它可能需要更多验证或者可以更简单更好,但我正在尝试为您提供解决此问题的方法

在您的平面文件连接管理器组件中,您有一个 属性,我忘记了它的名字,您可以在其中设置行分隔符({CR}{LF}{LF}{CR}, ...等等).

请尝试调整一下属性我认为它会起作用。

我没有 SSIS 经验,但作为 ETL 开发人员,我遇到过很多次。所以我的建议可能无法帮助您解决问题,但希望能为您指明正确的方向

  • 如果问题字段有文本限定符(单引号或双引号 通常)并且 SSIS 支持使用它
  • 还有如果有一个选项 强制 SSIS 使用除 LF(本例中为 CRLF)以外的不同记录结尾分隔符,我会使用它(希望问题字段文本中没有 CRLF)
  • 如果问题字段不是最后一个字段,您可以通过将整个记录作为单个 LF 分隔字段读取来计算分隔符的数量 识别并过滤掉问题记录(如果它们很少) 并尝试将它们缝合起来
  • 如果可能的话,单独读取文件 记录(如果 SSIS 有一个选项)并替换所有 LF,前提是 CR 来自源的记录分隔符的一致结尾

感谢您提出的所有建议。结果是供应商将文件的编码从 Ascii 更改为 unicode。更改包以读取正确的编码就可以了。

我遇到了类似的问题。我有一个以 LF 作为终止符的 CSV 文件。但是,客户端在两列中也有 CRLF,这导致了“未找到列的定界符”错误。

我花了几天时间在谷歌上搜索解决方案并反复试验,但我成功了。

最后,我需要两个脚本组件。

在第一个脚本组件中,我有一个名为 Output0 string 的列,长度为 4000。在脚本中(见下文)我使用 ReadToEnd 加载数据,将 CRLF 替换为空字符串,然后拆分为以 LF 作为终止符的行。

using System.IO;
using System.Text;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    private StreamReader textReader;
    private string collateralFile;

public override void AcquireConnections(object Transaction)
{

    IDTSConnectionManager100 connMgr = this.Connections.Collateral;
    collateralFile = (string)connMgr.AcquireConnection(null);

}

public override void PreExecute()
{
    base.PreExecute();


}

public override void CreateNewOutputRows()
{

    StreamReader textReader = new StreamReader(collateralFile);
    string collatFile = textReader.ReadToEnd();


    collatFile = collatFile.Replace("\r\n", " ");
    
    String[] lines = collatFile.Split(new char[] { '\n' });
    textReader.Close();


        string nextLine;



        for (int i = 0; i < lines.Length; i++)
        {
            if (lines[i] != null)
            {
                nextLine = lines[i];

                if (!String.IsNullOrEmpty(nextLine))
                {
                    Output0Buffer.AddRow();
                    Output0Buffer.Output0 = nextLine;

                }
            }
          }

        }
    }

我尝试再次将它分成列,但它返回空值,因此在第二个脚本组件中我创建了我的列并在脚本中将数据加载到它们中。

public override void Input0_ProcessInputRow(Input0Buffer Row)
{

String[] columns = Row.Output0.Split(',');

Row.Description = columns[0];
Row.LegalDescription = columns[1];
Row.Address1ParsedLine1 = columns[2];
Row.Address1ParsedLine2 = columns[4];
Row.Address1ParsedCityname = columns[5];
Row.Address1ParsedStatecode = columns[6];
Row.Address1ParsedPostalcode = columns[7];
}