StringBuilder and Get-Content

This topic contains 3 replies, has 3 voices, and was last updated by  Joakim Svendsen 3 years, 9 months ago.

  • Author
    Posts
  • #11804

    Stephen Yeadon
    Participant

    I have a question. Why would using StringBuilder to append Get-Content produce a System.Object when $StringBuilder.ToString() is called. See below.


    $stringBuilder = New-Object System.Text.StringBuilder
    $content = Get-Content -Path C:\temp\file.txt
    $stringBuilder.Append($content)
    $stringBuilder.ToString() # System.Object[]

    If I force the $Content to be a string, $stringBuilder.ToString() will return the content of the file but all formatting is lost.


    [string]$content = Get-Content -Path C:\temp\file.txt

    or

    $stringBuilder.Append([string]$content)

    My question is why and how could I fix this? The code is used in a ForEach-Object loop to append files to a file in a particular order. I may be comming at this from a more c# point of view.

    Thank in advance...

  • #11805

    Dave Wyatt
    Moderator

    By default, Get-Content outputs one line at a time. When you pass it directly to a method (or assign it to a variable), you get an array. You have a couple of options, here: you can use Get-Content's -Raw switch (available in PowerShell 3.0 or later) to make it return the entire file as a single String, or you can use a ForEach-Object loop to append each line to the StringBuilder, one at a time.

    I'm not sure what you're using the StringBuilder for here; just calling ToString() on it doesn't gain you anything over simply assigning the output from Get-Content -Raw straight to a String variable. Also, keep in mind that StringBuilder's methods mostly return a reference to the StringBuilder itself, so they can be chained together (ie, $stringBuilder.Append('Something').Append('Something Else') ), so you may want to suppress that output in your script by assigning it to a variable, casting it to void or piping to Out-Null (whatever your preference.)

    # Using -Raw
    $stringBuilder = New-Object System.Text.StringBuilder
    
    $content = Get-Content -Path C:\temp\file.txt -Raw
    $null = $stringBuilder.Append($content)
    $stringBuilder.ToString()
    
    # Using a loop
    $stringBuilder = New-Object System.Text.StringBuilder
    
    Get-Content -Path C:\temp\file.txt |
    ForEach-Object {
        $null = $stringBuilder.AppendLine($_)
    }
    
    $stringBuilder.ToString()
    
  • #11806

    Stephen Yeadon
    Participant

    Thank you -Raw did the trick. I hadn't tried that as I thought the problem lay with the string builder object, i didn't realize that get-content worked that way.

  • #11811

    Joakim Svendsen
    Participant

    Just for the sake of enlightenment: You could also have used the -join operator and joined the Get-Content-produced array of strings (Get-Content actually adds lots of other metadata, so they're not technically just strings) with newlines, as demonstrated below. It preserves the formatting of my dummy XML file. Otherwise Dave got it all covered, I think. I'm not sure what you need StringBuilder for(?). The -Raw parameter to Get-Content was added in PowerShell version 3, so you'd need something like this for earlier versions of PowerShell.

    PS D:\temp> gc .\xml.xml
    
      
        foo
        bar
      
    
    PS D:\temp> (New-Object Text.StringBuilder).Append(((gc xml.xml) -join "`n")).ToString()
    
      
        foo
        bar
      
    
    

You must be logged in to reply to this topic.