2016-10-01 16 views
0

我需要讀取,修改並更新相同功能中的某些文件。理想的解決方案(見下文)無法工作,這是錯誤的。 「最差」解決方案有效。最短的代碼來讀取文件,然後更新它?

-- Ex. "Pseudocode" - Doesn't work. 
ideal = let pathFile = "C:\\TEMP\\Foo.txt" 
      in readFile pathFile >>= writeFile pathFile . (++ "!") 

-- It works. 
worst = do 
    let pathFile = "C:\\TEMP\\Foo.txt" 
    h <- openFile pathFile ReadMode 
    cs <- hGetContents h 
    (temp_Foo,temp_handle) <- openTempFile pathFile 
    hPrint temp_handle $ cs ++ "!" 
    hClose temp_handle 
    removeFile pathFile 
    renameFile temp_Foo pathFile 

我希望避免2010年「簡單而醜陋的解決方法」,由裏德·波頓建議:

doit file = do 
    contents <- readFile file 
    length contents `seq` (writeFile file $ process contents) 

有沒有更好的解決辦法?

+0

那麼,你可以有一個管道/管道解決方案。 :) – Sibi

+0

@Sibi這些庫很大。我認爲這需要很長時間才能掌握。另外,我不認爲用大炮殺死蚊子。 –

+1

@AlbertoCapitani你不需要大炮來殺死蚊子 - 但是你也不需要超級計算機(按70年代的標準)撥打電話。 – leftaroundabout

回答

1

ideal的問題在於它會懶散地讀取字符串,即文件在內存中未完全存在,而您已經嘗試再次打開該文件進行寫入。

這種lazyness的是現在被廣泛認爲是一個壞主意 - 如果你真的需要這樣讀的,你去的能力,然後conduit/pipes是你想要的。

在你的例子中,你並不需要懶惰,儘管儘管如此,除非該文件太大而不能保證一次在內存中。所以,你可以只使用readFile,但需要使它嚴格:一個手動的方式做這將是

ideal = do 
    fc <- readFile pathFile 
    length fc `seq` writeFile pathFile (fc++ "!") 
where pathFile = "C:\\TEMP\\Foo.txt" 

在這裏,我用length,以確保該字符串是真正評估到最後。在保證同樣的事情,一個更好的方法是使用deepseq

ideal = do 
    fc <- readFile pathFile 
    fc `deepseq` writeFile pathFile (fc++ "!") 

...或者,如果你想將它指向自由,

ideal = readFile pathFile >>= (writeFile pathFile . (++ "!") $!!) 

注意的readFile更高效更現代的變種類型比String - 特別是,Data.Text.readFile - 不需要這些,因爲它們嚴格的開箱即用。因此,以下只是工作,而且可能是最好的解決辦法:

{-# LANGUAGE OverloadedStrings #-} 

import Prelude hiding (readFile, writeFile) 
import Data.Text.IO 
import Data.Monoid ((<>)) 

main :: IO() 
main = readFile pathFile >>= writeFile pathFile . (<> "!") 
where pathFile = "/tmp/foo.txt" 

在Haskell中,所有的「交錯IO」的最早期實際上是基於lazyness,因此老的庫有些淹沒了它。

相關問題