SSIS читает LF как терминатор, когда он установлен как CRLF

с использованием SSIS 2012. Мой диспетчер соединений с плоскими файлами У меня есть файл с разделителями, в котором разделитель строк установлен на CRLF, но когда он обрабатывает файл, у меня есть текстовый столбец, в котором есть LF. Это заставляет его читать это как терминатор строки, вызывающий сбой. Любые идеи?


person vin    schedule 24.05.2017    source источник
comment
я неправильно понял ваш вопрос. Я думал, что ваш плоский файл содержит разделитель нескольких строк. я отредактировал свой ответ взгляни   -  person Hadi    schedule 02.06.2017


Ответы (5)


У меня нет опыта работы с SSIS, но как разработчик ETL я сталкивался с этим много раз. Так что мои предложения могут не помочь вам решить проблему, но, надеюсь, укажут вам в правильном направлении.

  • Если проблемное поле имеет текстовый квалификатор (обычно одинарные или двойные кавычки) и SSIS поддерживает его, используйте
  • Также, если есть возможность заставить SSIS использовать другой разделитель конца записи, отличный от LF (CRLF в этом случае), я бы использовал его (надеюсь, в тексте поля проблемы нет CRLF)
  • Если проблемное поле не является последним полем, вы можете подсчитать количество ограничителей, прочитав всю запись как одно поле с разделителями LF, чтобы идентифицировать и отфильтровать проблемные записи (если их всего несколько) и попытаться сшить их назад
  • Если возможно, прочтите файл как одну запись (если у SSIS есть опция) и замените все LF, при условии, что CR соответствует конечному разделителю записи от источника
person AlwaysConfused    schedule 01.06.2017

Прежде чем ответить, я не думаю, что столбец содержит только LF, потому что, если разделитель строк равен CRLF, он не будет рассматривать его как разделитель. Так что, вероятно, CRLF, но я дам решение для двух случаев (CRLF или LF)

Решение

Вы можете исправить эту ситуацию, выполнив следующие действия:

  1. Сначала в диспетчере соединений с неструктурированными файлами добавьте только один столбец (типа DT_STR и длины 4000), так что вы будете рассматривать каждую строку как один столбец.
  2. В задачу потока данных вы должны добавить компонент Script, который фиксирует файловую структуру. и разделите строку на столбцы.

Простой тест

Я буду рассматривать плоский файл со следующим содержанием

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. First i will add a flat file connection manager with the following options:
    • Row Delimiter = {CRLF}
    • Разделитель строки заголовка = {CRLF}

введите описание изображения здесь

  1. В задаче DataFlow я добавлю Flat File Source, 2 x Script Component, OLEDB 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. Во втором сценарии COmponent я разделит каждую строку на столбцы

введите описание изображения здесь

    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

Важное примечание: предоставленный код не оптимален, может потребоваться дополнительная проверка или он может быть проще и лучше, но я пытаюсь дать вам способ решения этой проблемы.

person Hadi    schedule 27.05.2017
comment
Это не сработает, потому что OP заявил, что дополнительный LF находится в столбце, что для меня означает, что читатель перестает читать строку в этот момент. Удаление CR с концов не повлечет за собой никаких изменений, так как он все равно будет читать лишние ложные строки для тех строк, которые содержат символы LF в столбцах. - person Bill Hileman; 01.06.2017
comment
Спасибо за замечание. Я неправильно понял вопрос. Я изменю свой ответ. Большое спасибо - person Hadi; 01.06.2017

спасибо за все предложения. Оказалось, что производитель изменил кодировку файла с Ascii на unicode. изменение пакета для чтения правильной кодировки помогло.

person vin    schedule 05.06.2017
comment
Просто примите этот ответ, даже если он ваш, поэтому вопрос будет отмечен как отвеченный. Также предоставленные ответы полезны, и эти люди тратят время на решение вашей проблемы, поэтому приятно проголосовать за ответы. - person Yahfoufi; 08.06.2017

В вашем компоненте Диспетчера соединений с плоскими файлами у вас есть свойство, имя которого я забыл, в нем вы можете установить разделитель строк ({CR}{LF}, {LF}, {CR}, ... и т. Д.).

Пожалуйста, попробуйте настроить это свойство, я думаю, это сработает.

person Jardel Novaes    schedule 31.05.2017
comment
Это неправда! Я много использовал SSIS на своей последней работе, но у меня их нет на моей текущей работе, поэтому я не мог проверить свойство и ответил мысленно. Я не думаю, что это хорошая идея - понижать голос, когда кто-то пытается помочь, и не давать неправильный ответ, кстати, это всего лишь мой вариант. Я действительно не знаю, как этот другой ответ. Не могли бы вы сообщить, пожалуйста? Я думаю, что это будет обычным делом, если у вас будет другой навес - person Jardel Novaes; 01.06.2017

У меня была аналогичная проблема. У меня был файл CSV с LF в качестве терминатора. Однако у клиента также был CRLF в двух столбцах, и это вызывало ошибку разделителя для столбца не найден.

Мне потребовалось несколько дней поиска решений в Google, проб и ошибок, но все заработало.

В итоге мне понадобились два скриптовых компонента.

В первом компоненте Script у меня был столбец с именем 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];
}
person goodeyebrian    schedule 30.07.2020