问题
I have been assigned a task to write a program that will:
Open a file.
Read the content.
Replace a specific word with another word.
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.
回答1:
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.
回答2:
I retained most of your original code, although it's not very idiomatic. If you use use
with disposable resources, .NET will clean up after you. See for example F# Docs and Fun&Profit, the latter also has a nice section on Expressions and syntax.
If you execute your code, you should get System.IO.IOException:
Unhandled Exception: System.IO.IOException: The process cannot access the file 'C:\Users\xcs\Documents\Visual Studio 2015\Projects\StackOverflow6\ConsoleApplication11\bin\Release\testout.txt' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.StreamWriter.CreateFile(String path, Boolean append, Boolean checkHost) at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize, Boolean checkHost) at System.IO.StreamWriter..ctor(String path, Boolean append) at System.IO.File.CreateText(String path) at Program.op@46(Unit unitVar0) in C:\Users\xcs\Documents\Visual Studio 2015\Projects\StackOverflow6\ConsoleApplication11\Program.fs:line 74
at Program.main(String[] argv) in C:\Users\xcs\Documents\Visual Studio 2015\Projects\StackOverflow6\ConsoleApplication11\Program.fs:line 83
It starts at line 83, which is the call to the function, goes to line 74. Line 74 is the following: let readerWrite = File.CreateText(filename)
. Nowhere in your code have you closed reader
. There is also another problem, you're opening a StreamWriter
with File.CreateText
. And then you're trying to write to this opened stream with File.WriteAllText
, which opens the file, writes to it and closes it. So a bunch of IO handles are floating around there...
To quickly fix it consider the following:
//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
//Opens a stream to read the file
//let reader = File.OpenText filename
//Reads the file, and replaces the needle.
let printFile (filename:string) (needle:string) (replace:string) =
let mutable saveLine = ""
use reader = File.OpenText filename //use will ensure that the stream is disposed once its out of scope, i.e. the functions exits
while not(reader.EndOfStream) do
let line = reader.ReadLine ()
let lineReplace = line.Replace(needle,replace)
saveLine <- saveLine + lineReplace + "\r\n" //you will need a newline character
printfn "%s" lineReplace
saveLine
//Writes to the file
let editFile filename saveLine =
File.WriteAllText(filename,saveLine) //you don't need a stream here, since File.WriteAllText will open, write, then close the file
let saveLine = printFile filename needle replace //read the file into saveLine
editFile filename saveLine //write saveLine into the file
It does a couple of things:
- creates the
StreamReader
inside theprintFile
- binds it to reader with
use
, not let, to ensure it is closed once we don't need it anymore - add a linefeed to the string, since you insist rebuilding a mutable string
- encapsulates the mutable
saveLine
inside the function - passes the needle and replace arguments explicitly
- returns a new string to be used in 7.
- gets rid of the
Streamwriter
by usingFile.WriteAllText
and also passes in explicitly the filename and the string to write
来源:https://stackoverflow.com/questions/40617236/how-to-close-a-stream-properly