如何正确关闭流?

时间:2016-11-15 18:34:29

标签: f# stream streamreader streamwriter

我被分配了一个编写程序的任务:

  1. 打开文件。

  2. 阅读内容。

  3. 用另一个单词替换特定单词。

  4. 将更改保存到文件中。

  5. 我确信我的代码可以打开,阅读和替换单词。当我添加“将更改保存到文件” - 部分时,会出现此问题。这是代码:

    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)
    

    我收到错误消息“在路径上共享违规...”,这让我相信阅读流没有正确关闭。我试过玩我的代码结构并为.NET库尝试了不同的东西,但我总是得到相同的错误消息。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

通常通过调用Stream.Close()或处理它们来关闭流。

System.IO具有从/到行数组读取或写入完整文件的方法。这会将操作缩短为:

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

您使用的是哪些文档?查看the MSDN documentation for System.IO和类似的MSDN文档,了解.NET / CLR中的各种内容;这些答案很快就会回答这个问题。

答案 1 :(得分:1)

我保留了大部分原始代码,虽然它不是非常惯用的。如果您使用use一次性资源,.NET将在您之后清理。例如,请参阅F# DocsFun&Profit,后者在Expressions and syntax上也有一个很好的部分。

如果执行代码,则应该获得System.IO.IOException:

  

未处理的异常:System.IO.IOException:进程无法访问   文件'C:\ Users \ xcs \ Documents \ Visual Studio   2015年\项目\ StackOverflow6 \ ConsoleApplication11 \ BIN \发布\ testout.txt”   因为它正被另一个进程使用。在   System.IO .__ Error.WinIOError(Int32 errorCode,String maybeFullPath)
  在System.IO.FileStream.Init(字符串路径,FileMode模式,FileAccess   访问,Int32权限,布尔useRights,FileShare共享,Int32   bufferSize,FileOptions选项,SECURITY_ATTRIBUTES secAttrs,String   msgPath,Boolean bFromProxy,Boolean useLongPath,Boolean checkHost)
  在System.IO.FileStream..ctor(字符串路径,FileMode模式,FileAccess   访问,FileShare共享,Int32 bufferSize,FileOptions选项,字符串   msgPath,Boolean bFromProxy,Boolean useLongPath,Boolean checkHost)
  在System.IO.StreamWriter.CreateFile(String path,Boolean append,   System.IO.StreamWriter..ctor(String path,Boolean checkHost)   布尔附加,编码编码,Int32 bufferSize,布尔值   checkHost)在System.IO.StreamWriter..ctor(String path,Boolean   附加)在System.IO.File.CreateText(String path)at   C:\ Users \ xcs \ Documents \ Visual中的Program.op@46(Unit unitVar0)   工作室   2015 \ Projects \ StackOverflow6 \ ConsoleApplication11 \ Program.fs:第74行   在C:\ Users \ xcs \ Documents \ Visual中的Program.main(String [] argv)   工作室   2015 \ Projects \ StackOverflow6 \ ConsoleApplication11 \ Program.fs:第83行

从第83行开始,这是对函数的调用,转到第74行。第74行如下:let readerWrite = File.CreateText(filename)。您的代码中没有任何地方关闭reader。还有一个问题,即您使用StreamWriter打开File.CreateText。然后你试图用File.WriteAllText写入这个打开的流,打开文件,写入并关闭它。因此,一堆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


//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

它做了几件事:

  1. StreamReader
  2. 中创建printFile
  3. 使用use将其绑定到读者,不要让它一旦我们不再需要它就确保关闭
  4. 为字符串添加换行符,因为您坚持重建可变字符串
  5. 将mutable saveLine封装在函数
  6. 传递针并明确替换参数
  7. 返回要在7.中使用的新字符串。
  8. 使用Streamwriter删除File.WriteAllText,并明确传入文件名和要写的字符串