2016-11-15 141 views
1

我被分配一个任务,写一个程序,将:如何正确关闭流?

  1. 打开文件。

  2. 阅读内容。

  3. 用另一个词替换某个单词。

  4. 保存对文件的更改。

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

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

流通常通过致电Stream.Close()或处置它们而关闭。

System.IO有方法来读取或写入线阵列的完整文件。这会缩短操作的步骤:

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

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

+0

哇,我也没想到,这个代码可以在3线写入。我认为你的代码很棒 - 但是,我觉得我仍然需要用我的代码找到问题。我试着调用Stream.Close(),但我仍然得到相同的错误信息。我什至尝试改变File.ReadAllLines(因为ReadAllLines在阅读后关闭文件)。我认为我的“写入文件”代码是错误的。我在msdn的网站上尝试阅读“如何:将文本写入文件”,但没有f#示例。你能看到我的代码有什么问题吗? – Hako

+0

@Hakan我认为你应该接受Vandroiy的答案,因为它使用ReadAlllines和WriteAllLines,这是解决这类问题的最简单方法。关于你的问题,请看我的帖子。 – s952163

+1

我不能放弃的另一个评论:看看这个答案跟问题定义有多接近:第1行:(打开文件)和阅读内容,第2行:替换单词,第3行:写内容。它确实很漂亮。 – s952163

2

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

如果你执行你的代码,你应该得到System.IO.IOException:

未处理的异常信息:System.IO.IOException:该进程无法访问 文件“C:\用户\ XCS \文件\ Visual Studio 2015 \ Projects \ StackOverflow6 \ ConsoleApplication11 \ bin \ Release \ testout.txt' 因为它正在被另一个进程使用。在 System.IO .__ Error.WinIOError(的Int32的errorCode,字符串maybeFullPath)
在System.IO.FileStream.Init(字符串路径,的FileMode模式,FileAccess的 访问,权限的Int32,布尔useRights,文件共享份额,的Int32 BUFFERSIZE, FileOptions选项,SECURITY_ATTRIBUTES secAttrs,字符串 MSGPATH,布尔bFromProxy,布尔useLongPath,布尔checkHost)
在System.IO.FileStream..ctor(字符串路径,的FileMode模式,FileAccess的 访问,文件共享份额,缓冲区大小的Int32,FileOptions选项,字符串 msgPath,布尔bFromProxy,布尔useLongPath,布尔checkHost)
at System.IO.StreamWriter.CreateFile(String path,Boolean append, 布尔checkHost)在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 [email protected](Unit unitVar0)in C:\ Users \ xcs \ Documents \ Visual Studio 2015 \ Projects \ StackOverflow6 \ ConsoleApplication11 \ Program.fs:line 74
at Program.main(String [] argv)in C:\用户\ XCS \文档\ Visual Studio中 2015年 \项目\ StackOverflow6 \ ConsoleApplication11 \ Program.fs:线83

它开始于线83,其是对函数的调用,请转到第74行。第74行如下:let readerWrite = File.CreateText(filename)。你的代码中没有任何地方关闭了reader。还有另一个问题,你打开StreamWriterFile.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. 创建内部的StreamReaderprintFile
  2. 将它绑定到use的阅读器,不让它确保一旦我们不再需要它就关闭
  3. 换行符添加到字符串,既然你坚持重建一个可变的字符串
  4. 封装功能
  5. 内的可变saveLine通过针和替换的参数明确
  6. 返回一个新字符串到7
  7. 使用
  8. 被使用File.WriteAllText摆脱Streamwriter,并也通过在明确的文件名和字符串写入
+0

非常好!我们还没有被引入“使用”绑定,但我现在可以看到它是如何派上用场的。谢谢。 – Hako

+1

为什么除了已经返回一个字符串的'ReadLine'外还使用'string'函数? – Sehnsucht

+0

@Sehnsucht好评!是的先生。我知道,我只是不想过分榨取OP的风格。 ;-)我认为这是工作后应该进入codereview,但低于Vandroiy已经压缩了很多。 – s952163