Search code examples
f#streamstreamreaderstreamwriter

How to close a stream properly?


I have been assigned a task to write a program that will:

  1. Open a file.

  2. Read the content.

  3. Replace a specific word with another word.

  4. Save the changes to the file.

I know for sure that my code can open, read and replace words. The problem occurs when i add the "Save the changes to the file" - part. Here is the code:

open System.IO

//Getting the filename, needle and replace-word.
System.Console.WriteLine "What is the name of the file?"
let filename = string (System.Console.ReadLine ())

System.Console.WriteLine "What is your needle?"
let needle = string (System.Console.ReadLine ())

System.Console.WriteLine "What you want your needle replaced with?"
let replace = string (System.Console.ReadLine ())   

//Saves the content of the file
let mutable saveLine = ""   

//Opens a stream to read the file
let reader = File.OpenText filename

//Reads the file, and replaces the needle.
let printFile (reader : System.IO.StreamReader) =
  while not(reader.EndOfStream) do
    let line = reader.ReadLine ()
    let lineReplace = line.Replace(needle,replace)
    saveLine <- saveLine + lineReplace
    printfn "%s" lineReplace

//Opens a stream to write to the file
let readerWrite = File.CreateText(filename)

//Writes to the file
let editFile (readerWrite : System.IO.StreamWriter) =
  File.WriteAllText(filename,saveLine)

printf "%A" (printFile reader)

I get the error message "Sharing violation on path...", which makes me believe that the reading stream do not close properly. I have tried playing around with the structure of my code and tried different things for the .NET library, but i always get the same error message. Any help is much appreciated.


Solution

  • Streams are normally closed by calling Stream.Close() or disposing them.

    System.IO has methods to read or write complete files from/to arrays of lines. This would shorten the operation to something like this:

    File.ReadAllLines filePath
    |> Array.map (fun line -> line.Replace(needle, replace))
    |> fun editedLines -> File.WriteAllLines(filePath, editedLines)
    

    What documentation are you using? Have a look at the MSDN documentation for System.IO and the similar MSDN documentations for various things in .NET/the CLR; these answer questions like this one quickly.