SSIS 将 LF 设置为 CRLF 时将其读取为终止符
SSIS reading LF as terminator when its set as CRLF
使用 SSIS 2012。我的平面文件连接管理器我有一个带分隔符的文件,其中行分隔符设置为 CRLF
,但是当它处理该文件时,我有一个文本列 LF
在里面。这导致它将其读取为导致它失败的行终止符。有什么想法吗?
在回答之前,我不认为该列仅包含 LF
因为如果行分隔符是 CRLF
它不会将其视为分隔符。所以它可能是 CRLF
,但我会针对这两种情况(CRLF 或 LF)给出解决方案
解决方案
您可以通过以下步骤解决此问题:
- 首先在平面文件连接管理器中仅添加一列(类型
DT_STR
和长度 4000
),因此您会将每一行视为一列。
- 在数据流任务中,您必须添加一个修复文件结构的脚本组件。并将行拆分为列。
简单测试
我会考虑一个包含以下内容的平面文件
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}
- 首先,我将使用以下选项添加平面文件连接管理器:
- 行分隔符 = {CRLF}
- Header 行分隔符 = {CRLF}
在 DataFlow 任务中,我将添加一个 Flat File Source
、2 x Script Component
、OLEDB Destination
在第一个脚本组件中,我将标记 Column0
作为输入,我将添加 5 个输出列 ID,Name,DOB,Notes,ClassID
,并将输出同步输入设置为 None
在第一个脚本组件中,我将编写一个脚本,将每一行存储在内存变量中,并在行完成且存在另一行时将其分配给输出行。
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
在第二个脚本组件中,我会将每一行拆分为列
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];
}
使用 SSIS 2012。我的平面文件连接管理器我有一个带分隔符的文件,其中行分隔符设置为 CRLF
,但是当它处理该文件时,我有一个文本列 LF
在里面。这导致它将其读取为导致它失败的行终止符。有什么想法吗?
在回答之前,我不认为该列仅包含 LF
因为如果行分隔符是 CRLF
它不会将其视为分隔符。所以它可能是 CRLF
,但我会针对这两种情况(CRLF 或 LF)给出解决方案
解决方案
您可以通过以下步骤解决此问题:
- 首先在平面文件连接管理器中仅添加一列(类型
DT_STR
和长度4000
),因此您会将每一行视为一列。 - 在数据流任务中,您必须添加一个修复文件结构的脚本组件。并将行拆分为列。
简单测试
我会考虑一个包含以下内容的平面文件
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}
- 首先,我将使用以下选项添加平面文件连接管理器:
- 行分隔符 = {CRLF}
- Header 行分隔符 = {CRLF}
在 DataFlow 任务中,我将添加一个
Flat File Source
、2 xScript Component
、OLEDB Destination
在第一个脚本组件中,我将标记
Column0
作为输入,我将添加 5 个输出列ID,Name,DOB,Notes,ClassID
,并将输出同步输入设置为None
在第一个脚本组件中,我将编写一个脚本,将每一行存储在内存变量中,并在行完成且存在另一行时将其分配给输出行。
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
在第二个脚本组件中,我会将每一行拆分为列
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];
}