2016-11-15 107 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