SSIS 脚本任务中字符串生成器的 System.out 内存异常

发布于 2024-12-11 08:37:23 字数 1870 浏览 0 评论 0原文

我在 SSIS 脚本任务中使用 VB 脚本将标头和标尾添加到平面文件中。代码工作正常,直到最近我遇到一个问题,文件中的行比平常多,导致脚本任务失败并出现错误“错误:

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)` 

任何人都可以帮我解决问题吗?我认为而不是“字符串生成器”我需要使用其他字符串相关的方法。我收到错误 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

I am using a VB script in SSIS Script Task to add header and Trailer to a flat file. The code was working fine until recently i came across a problem where the rows in the file are more than usual and resulting in a failure on script task with error`Error:

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)` 

Can any one help me in fixing the problem please.I think instead of "String Builder" i need to use other string related method. I am getting error at
fileContents.Append(File.ReadAllText(Dts.Connections("DestinationConnection").ConnectionString))

Here is my code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

百思不得你姐 2024-12-18 08:37:23

好吧,一种简单的方法就是避免使用 StringBuilder:使用 File.CreateText 打开一个 TextWriter,写入第一行,然后写入 File.ReadAllText(...),然后写入最后一行。

但是,这只会节省您一些内存 - 它会将所需的内存大致减半,因为您在StringBuilder 中都不需要它> 一个字符串(我认为现在会发生这种情况)。

更好的替代方法是:

  • 打开写入器
  • 写入标题行
  • 打开其他文件进行读取
    • 循环文件,一次读取一大块字符并将其写入新文件,直到完成
    • 隐式关闭其他文件(为此使用 Using 语句)
  • 写入尾行
  • 隐式关闭写入(使用 Using 语句)

这样,即使您有巨大的文件,一次也只需要内存中的一小块数据。

Well, one simple way would be to just avoid the StringBuilder: open a TextWriter with File.CreateText, write the first line, then write File.ReadAllText(...), then write the final line.

However, that will only save you some memory - it will roughly halve the memory required, as you won't need it in both the StringBuilder and a string (which is what I think will happen now).

A much better alternative would be to:

  • Open the writer
  • Write the header line
  • Open the other file for reading
    • Loop over the file, reading a chunk of characters at a time and writing it to the new file, until you're done
    • Close the other file implicitly (use a Using statement for this)
  • Write the trailing line
  • Close the write implicitly (use a Using statement)

That way even if you've got huge files, you only need a small chunk of data in memory at a time.

稳稳的幸福 2024-12-18 08:37:23

问题是 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

您可能仍然对 fileContents StringBuilder 有问题。但显示的原始错误是从 File.ReadAllText 方法引发的。所以希望这能起到作用。

如果没有,我就会忘记 fileContents StringBuilder 并写出标题。然后逐行从文件中读取并逐行写出,最后写入页脚。

The problem is File.ReadAllText has limitations when it comes to reading a large file because the entire file is read into memory.

What you will need to do is replace the File.ReadAllText with reading the file line by line and append it accordingly.

EDITED FOR AN EXAMPLE:

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

It's possible you may still have an issue with the fileContents StringBuilder. The original error shown though was thrown from the File.ReadAllText method. So hopefully, this does the trick.

If not, I would just forget about the fileContents StringBuilder all together and write out the header. Then read from the file line by line and write it out line by line, then finally write the footer.

烛影斜 2024-12-18 08:37:23

另一种(更类似于 SSIS)解决方案是创建一个数据流任务,该任务读取现有文件,通过添加页眉和页脚的脚本组件将其传输,然后将其写入文件系统。它在 SSIS 2005 中可能如下所示:

在此处输入图像描述

脚本组件将是一个具有其 SynchronousInputID 的转换输出设置为 False,以便它可以生成页眉和页脚行:

在此处输入图像描述

转换的 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 的流功能。

An alternative (and much more SSIS-like) solution would be to create a Data Flow Task that reads your existing file, pipes it through a Script Component that adds the header and footer, and writes it to the file system. Here's what it might look like in SSIS 2005:

enter image description here

The Script Component will be a Transformation with the SynchronousInputID of its output set to False, so that it can generate header and footer rows:

enter image description here

And the VB source of the transform should look something like this:

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

This lets you use the streaming capabilities of SSIS to your advantage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文