[英]Write at the beginning of a file in Haskell
我試圖在文件的開頭添加一個數字,但函數“appendFile”添加在文件的末尾。
我寫了這個,但它沒有用。
myAppendFile file = do x <- readFile file
writeFile file "1"
appendFile file x
return x
當我做:
*main> myAppendFile "File.txt"
錯誤是
the ressource is busy (file is locked)
那么如何在文件的開頭寫一些東西呢?
正如Gabriel指出的那樣,問題在於readFile
按需讀取文件內容,並且僅在文件內容被完全消耗時才關閉底層文件句柄。
解決方案是要求完整的文件內容,以便在執行writeFile
之前關閉處理程序。
簡答:使用嚴格包中的readFile 。
import qualified System.IO.Strict as SIO
import Data.Functor
myAppendFile :: FilePath -> IO String
myAppendFile file = do
x <- SIO.readFile file
writeFile file "1"
appendFile file x
return x
main :: IO ()
main = void $ myAppendFile "data"
另一個簡單的“黑客”實現這一點是使用seq
:
myAppendFile :: FilePath -> IO String
myAppendFile file = do
x <- readFile file
length x `seq` writeFile file "1"
appendFile file x
return x
seq ab
基本上只是b
加上當需要b
時, a
(在這種情況下length x
)在仔細檢查b
之前被評估為WHNF ,這是因為length
需要遍歷其參數(在這種情況下為x
)直到空列表[]
可以看到,因此需要完整的文件內容。
請記住,通過使用嚴格的IO,您的程序將在內存中保存所有文件內容(作為Char
的列表)。 對於玩具程序來說很好,但是如果你關心性能,你可以看看bytestring或text,具體取決於你的程序是處理字節還是文本(如果你想處理unicode文本)。 它們都比String
更有效。
我設法讓它工作,但我使用ByteString這是一個嚴格的數據類型:
import Data.ByteString.Char8 as B
myAppendFile file = do
x <- B.readFile file
B.writeFile file $ B.pack "1"
B.appendFile file x
return $ B.unpack x
main = myAppendFile "c:\\test.txt"
由於Haskell的懶惰,你的代碼給了你這個錯誤。 當您嘗試在文件中寫入內容時,數據未在x
完全讀出,因為haskell在該代碼點之前不需要x
值。 這就是為什么Haskell仍然掛起文件的原因。
還有一個觀察結果,如果你在此功能之前有另一個懶惰的讀取,請用嚴格的版本替換它,因為你會再次遇到麻煩。
傳統的方法也適用於Haskell。 創建一個新的臨時文件,將舊的字節流轉換為臨時文件,然后將臨時文件移到舊文件上。 您可以/應該使用ByteString
或其他一些方法來提高效率,但是您可以在塊中進行復制,而不是需要將所有內容讀入內存然后再將其吐出。 我認為pipes
和conduit
都提供了應該讓這更令人愉快的接口。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.