Исключение System.out памяти для String Builder в задаче сценария служб SSIS - PullRequest
0 голосов
/ 21 октября 2011

Я использую VB-скрипт в SSIS Script Task, чтобы добавить заголовок и трейлер в плоский файл.Код работал нормально до недавнего времени, я столкнулся с проблемой, когда строки в файле больше, чем обычно, что привело к ошибке задачи скрипта с ошибкой `Ошибка:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.String.GetStringForStringBuilder(String value, Int32 startIndex, Int32 length, Int32 capacity)
   at System.Text.StringBuilder.GetNewString(String currentString, Int32 requiredLength)
   at System.Text.StringBuilder.Append(Char[] value, Int32 startIndex, Int32 charCount)
   at System.IO.StreamReader.ReadToEnd()
   at System.IO.File.ReadAllText(String path, Encoding encoding)
   at System.IO.File.ReadAllText(String path)` 

Может ли кто-нибудь помочь мне вЯ решил, что вместо «String Builder» мне нужно использовать другой метод, связанный со строками.Я получаю ошибку в fileContents.Append (File.ReadAllText (Dts.Connections ("DestinationConnection"). ConnectionString))

Вот мой код:

Public Sub Main()

    Dim fileContents As New StringBuilder()
    Dim finalfile As String
    Dim firstline As String
    Dim lastline As String


    Dts.VariableDispenser.LockForRead("FirstLine")
    Dts.VariableDispenser.LockForRead("LastLine")

    Dts.VariableDispenser.LockForRead("FileName")

    firstline = CType(Dts.Variables("FirstLine").Value, String)
    finalfile = CType(Dts.Variables("FileName").Value, String)
    lastline= CType(Dts.Variables("LastLine").Value, String)


    'Write header, then append file contents and write back out.
    fileContents.AppendLine(String.Format("{0}", firstline))
      fileContents.Append(File.ReadAllText(Dts.Connections("DestinationConnection").ConnectionString))
    fileContents.AppendLine(String.Format("{0}", lastline))

    File.WriteAllText(finalfile, fileContents.ToString())

    Dts.TaskResult = ScriptResults.Success
End Sub

Ответы [ 3 ]

3 голосов
/ 21 октября 2011

Ну, одним простым способом было бы просто избежать StringBuilder: открыть TextWriter с помощью File.CreateText, написать первую строку, затем написать File.ReadAllText(...), а затем написать последнюю строку.

Однако, это только сэкономит вам некоторую память - это примерно вдвое уменьшит требуемую память, так как она вам не понадобится как в StringBuilder , так и * 1013.* строка (это то, что я думаю произойдет сейчас).

Гораздо лучшая альтернатива будет:

  • Открыть писатель
  • Введите строку заголовка
  • Откройте другой файл для чтения
    • Зациклите файл, считывая порцию символов за раз и записывая его в новый файл, пока не закончите
    • Неявное закрытие другого файла (для этого используйте оператор Using)
  • Запись завершающей строки
  • Неявное закрытие записи (используйте aUsing выражение)

Таким образом, даже если у вас есть большие файлы, вам нужен только небольшой кусок данных в памяти за раз.

1 голос
/ 21 октября 2011

Проблема в том, что File.ReadAllText имеет ограничения при чтении большого файла, поскольку весь файл считывается в память.

Вам нужно заменить File.ReadAllText на построчное чтение файла и добавить его соответствующим образом.

РЕДАКТИРОВАНИЕ ДЛЯ ПРИМЕРА:

Option Explicit
Dim oFSO, sFile, oFile, sText
Set oFSO = CreateObject("Scripting.FileSystemObject")
sFile = "your text file"
If oFSO.FileExists(sFile) Then
    Set oFile = oFSO.OpenTextFile(sFile, 1)
    Do While Not oFile.AtEndOfStream
        sText = oFile.ReadLine
        If Trim(sText) <> "" Then
            fileContents.AppendLine(sText)
        End If
    Loop
    oFile.Close
Else
    WScript.Echo "The file was not there."
End If

Возможно, у вас все еще есть проблема с файлом Content StringBuilder. Показанная первоначальная ошибка возникла из метода File.ReadAllText. Надеюсь, это поможет.

Если нет, я бы просто забыл о файле Content StringBuilder все вместе и выписал заголовок. Затем прочитайте из файла строку за строкой и запишите его строка за строкой, а затем напишите нижний колонтитул.

0 голосов
/ 21 октября 2011

Альтернативным (и гораздо более похожим на SSIS) решением было бы создание Задачи потока данных, которая считывает существующий файл, передает его через компонент Script, который добавляет верхний и нижний колонтитулы, и записывает его в файловую систему.Вот как это может выглядеть в SSIS 2005:

enter image description here

Компонент Script будет преобразованием с SynchronousInputID его выхода, установленным в False, чтобы он мог генерировать верхний и нижний колонтитулыстроки:

enter image description here

И источник преобразования VB должен выглядеть примерно так:

Public Class ScriptMain
    Inherits UserComponent
    Dim headerWritten As Boolean = False

    Public Overrides Sub IncomingRows_ProcessInputRow(ByVal Row As IncomingRowsBuffer)
        If Not headerWritten Then
            WriteHeader()
        End If
        OutgoingRowsBuffer.AddRow()
        OutgoingRowsBuffer.theLine = Row.theLine 
    End Sub

    Public Overrides Sub FinishOutputs()
        MyBase.FinishOutputs()
        WriteFooter()
    End Sub

    Private Sub WriteHeader()
        OutgoingRowsBuffer.AddRow()
        OutgoingRowsBuffer.theLine = "The First Header Line"
        headerWritten = True
    End Sub

    Private Sub WriteFooter()
        OutgoingRowsBuffer.AddRow()
        OutgoingRowsBuffer.theLine = "Here's a footer line"
        OutgoingRowsBuffer.AddRow()
        OutgoingRowsBuffer.theLine = "Here's another one"
    End Sub
End Class

Это позволяет вам использовать возможности потоковой передачи SSIS для вашегопреимущество.

...