簡體   English   中英

在Haskell中讀寫文件

[英]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.

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