If this is a duplicate question for this specific issue, forgive me and please kindly point me in the right direction - I have not seen this in Stack Overflow so far.
I'm using PowerShell
to run a set of commands as follows to find 'NUL' char's in a file. (-replace
works just fine - this is not my problem)
$findString = '\x00'
$replString = 'DERPS'
$foo = [IO.File]::ReadAllText("C:\SomeFile.txt")
$bar = $foo -replace $findString, $replString
[IO.File]::WriteAllText("C:\SomeFile_2.txt", $bar)
$Lines = Get-Content "C:\SomeFile_2.txt" -tail 10
#I have also used the following with the same effect:
#$Lines = Get-Content "C:\SomeFile_2.txt" |Select-Object -last 10
[IO.File]::WriteAllText("C:\FOOBARRED.txt", $Lines)
Set-Content "C:\NOT_FOOBARRED.txt" $Lines
What I'm experiencing is with [IO.File]
it concatenates the last 10 lines into one string:
Line 1 of 10 Line 2 of 10 Line 3 of 10 Line 4 of 10 Line 5 of 10 Line 6 of 10 Line 7 of 10 Line 8 of 10 Line 9 of 10 DERPSDERPSDERPSDERPSDERPS
With Set-Content
my output looks correct:
Line 1 of 10
Line 2 of 10
Line 3 of 10
Line 4 of 10
Line 5 of 10
Line 6 of 10
Line 7 of 10
Line 8 of 10
Line 9 of 10
DERPSDERPSDERPSDERPSDERPS
Can anyone explain what the difference is? Is it correct to assume the "WriteAllText" Command works when it's a raw format, but if it's processed in anyway it will accept the data as one large blob?
CodePudding user response:
[IO.File]::WriteAllText()
expects a single (potentially multiline) string as the argument to its contents
parameter.
By contrast, Get-Content -Tail 10
returns an array of strings (when captured in a variable), each containing a line from the file with the trailing newline stripped.
PowerShell performs many automatic type conversions, and while they're usually helpful, sometimes they're not: here, it automatically converts the array to a single-line string by concatenating the elements with a single space each[1], as the following example demonstrates:
PS> "$('line1', 'line2')" # stringify an array
line1 line2 # elements were joined with a space
This automatic stringification of the array stored in $Lines
in the context of your [IO.File]::WriteAllText()
call caused your problem.
Therefore, use [IO.File]::WriteAllLines()
instead (note: Lines rather than Text), which expects an array of strings and writes its elements as lines to the file, terminated with a (platform-native) newline each.
In other words: It acts like Set-Content
when given an array of strings, though note that in Windows PowerShell you'll end up with an ANSI-encoded file by default with Set-Content
, whereas .NET - and now PowerShell (Core) 7 , consistently - default to BOM-less UTF-8.
As an aside:
A PowerShell alternative to
[IO.File]::ReadAllText()
is to useGet-Content
with the-Raw
switch.You're already aware of
Set-Content
as the PowerShell alternative to[IO.File]::WriteAllLines()
. It can also act as an alternative to[IO.File]::WriteAllText()
if you pass it a single, multiline string and also specify the
-NoNewline
switch.
[1] A space character is the default, which you can override via the $OFS
preference variable, though that is rarely seen in practice.