簡體   English   中英

寫在Haskell中的文件的開頭

[英]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的列表)。 對於玩具程序來說很好,但是如果你關心性能,你可以看看bytestringtext,具體取決於你的程序是處理字節還是文本(如果你想處理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或其他一些方法來提高效率,但是您可以在塊中進行復制,而不是需要將所有內容讀入內存然后再將其吐出。 我認為pipesconduit都提供了應該讓這更令人愉快的接口。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM