ricky89
ricky89

Reputation: 1396

Use StreamWriter() to write to the same file as StreamReader()

I want to find and replace a certain string in a number of files. Some of these files can be relatively large so I am using the StreamReader class from the System.IO namespace.

The issue I have is that I don't want to have to write the new values to a new file (which is what I have currently). I want to just "update" the current files.

$currentValue = "B";
$newValue = "A";

# Loop through all of the directories and update with new details. 
foreach ($file in $Directories) {
    $streamReader = New-Object System.IO.StreamReader -Arg "$file"
    $streamWriter = [System.IO.StreamWriter] "$file"
    # Switching $streamWriter to the below works.
    # $streamWriter = [System.IO.StreamWriter] "C:\Temp\newFile.txt"

    while($line = $streamReader.ReadLine()){
        # Write-Output "Current line value is $line";
        $s = $line -replace "$currentValue", "$newValue"
        # Write-Output "The new line value is $s"
        $streamWriter.WriteLine($s);
    }

    # Close the streams ready for the next loop.
    $streamReader.close();
    $streamWriter.close();
}

Write-Output "The task has complete."

Does anyone know how I could go about doing the above?

Upvotes: 2

Views: 15638

Answers (2)

juan
juan

Reputation: 1

if ( $my_infile.Length -gt 0 ) {
  [string] $full_name_infile = $my_dir + "\" + $my_infile
  $f1 = Get-Content($full_name_infile) -ErrorAction Stop
  if ( $f1.count -gt 0 ) { 
       [string] $fout1_dir = $my_dir 
       [string] $fout1_name = $fout1_dir + "\"  + $my_infile + ".temp"
       $fmode = [System.IO.FileMode]::Append
       $faccess = [System.IO.FileAccess]::Write
       $fshare = [System.IO.FileShare]::None
       $fencode = [System.Text.ASCIIEncoding]::ASCII
       $stream1 = New-Object System.IO.FileStream $fout1_name, $fmode, $faccess, $fshare
       $fout1 = new-object System.IO.StreamWriter $stream1, $fencode
  }

  for ( $x=0; $x -lt $f1.count; $x++ ) {
    $line = $f1.Get( $x )
    if ( $line.length -eq 0 ) {
       $nop=1
    } else {
         if (  $line.Substring( $line.Length-1 , 1 ) -eq "," ) { $line = $line + " "; }
         $fout1.WriteLine( $line );
    }

  }
  $fout1.Close()
  $fout1.Dispose()
  move-item  $fout1_name $full_name_infile -force 
}  

Upvotes: -1

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200503

You can't read and write from/to the same file simultaneously. Not with StreamReader and StreamWriter, nor with any other usual method. If you need to modify an existing file and can't (or don't want to) read its entire content into memory you must write the modified content to a temporary file and then replace the original with the temp file after both files were closed.

Example:

$filename = (Get-Item $file).Name

$streamReader = New-Object IO.StreamReader -Arg $file
$streamWriter = [System.IO.StreamWriter] "$file.tmp"

...

$streamReader.Close(); $streamReader.Dispose()
$streamWriter.Close(); $streamWriter.Dispose()

Remove-Item $file -Force
Rename-Item "$file.tmp" -NewName $filename

Upvotes: 7

Related Questions