[英]Read and writing to file in Haskell
我正在嘗試讀取文件的內容,將文本轉為大寫,然后再寫回。
這是我編寫的代碼:
import System.IO
import Data.Char
main = do
handle <- openFile "file.txt" ReadWriteMode
contents <- hGetContents handle
hClose handle
writeFile "file.txt" (map toUpper contents)
return ()
但是,這不會將任何內容寫入文件,實際上,它甚至將其清除。
我進行了一些更改:
main = do
handle <- openFile "file.txt" ReadWriteMode
contents <- hGetContents handle
writeFile "file.txt" (map toUpper contents)
hClose handle
return ()
但是,我使錯誤resource busy (file is locked)
。 我怎樣才能使它起作用, 為什么在兩種情況下都不能起作用?
惰性IO不好,這通常被認為是Haskell的痛點。 基本上,直到您將其寫回到磁盤時,才對contents
進行評估,這時由於文件已關閉,因此無法評估內容。 您可以通過多種方式解決此問題,而無需借助額外的庫,您可以使用readFile
函數,然后在寫回之前檢查其長度:
import Control.Monad (when)
main = do
contents <- readFile "file.txt"
let newContents = map toUpper contents
when (length newContents > 0) $
writeFile "file.txt" newContents
我想說這段代碼實際上更好,因為您不會寫回已經為空的文件,這是沒有意義的操作。
另一種方法是使用流式庫, pipes
是帶有一些不錯的教程和扎實的數學基礎的流行選擇,這也是我的選擇。
@bwroga的答案是完全正確的。 這是建議方法的實現(寫入臨時文件和重命名):
import Data.Char (toUpper)
import System.Directory (renameFile, getTemporaryDirectory)
import System.Environment (getArgs)
main = do
[file] <- getArgs
tmpDir <- getTemporaryDirectory
let tmpFile = tmpDir ++ "/" ++ file
readFile file >>= writeFile tmpFile . map toUpper
renameFile tmpFile file
我認為您的問題是hGetContents是惰性的。 使用hGetContents時不會立即讀入文件的內容。 在需要時會讀取它們。
在第一個示例中,您打開文件並說您想要內容,然后在對它們執行任何操作之前先關閉文件。 然后,您寫入文件。 當您寫入現有文件時,內容將被清除,但是由於您關閉了文件,因此您將無權再訪問文件內容。
在第二個示例中,您打開文件,然后嘗試寫入文件,但是因為直到真正需要的內容(在轉換並寫回它們之后)才真正讀取內容,所以您最終嘗試對同一內容進行寫入和讀取同時歸檔。
您可以寫入一個名為file2.txt的文件,然后完成操作,刪除file.txt並將file2.txt重命名為file.txt
這里發生了幾件事
您在ReadWriteMode
打開了文件,但僅讀取了內容。 為什么不為兩者使用相同的句柄?
main = do
handle <- openFile "file.txt" ReadWriteMode
contents <- hGetContents' handle
hSeek handle AbsoluteSeek 0
hPutStr handle (map toUpper contents)
hClose handle
return ()
hGetContents
會將句柄置於半關閉狀態,因此您需要其他一些內容來讀取文件內容:
hGetContents' :: Handle -> IO String
hGetContents' h = do
eof <- hIsEOF h
if eof
then
return []
else do
c <- hGetChar h
fmap (c:) $ hGetContents' h
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.