我正在尝试创建一个待办事项列表 cli,该程序可以将这些任务保存到名为tasks.txt 的 .txt 文件中,但是,当我尝试添加新任务或查看 .txt 文件的内容时,它导致错误消息:“tasks.txt:withFile:资源繁忙(文件已锁定)”。据我所知,这个问题源于 Haskell 的惰性评估
-- Save tasks to a file
saveTasks :: [Task] -> IO ()
saveTasks tasks = writeFile "tasks.txt" (show tasks)
-- Load tasks from a file
loadTasks :: IO [Task]
loadTasks = do
fileExists <- doesFileExist "tasks.txt"
if fileExists
then do
content <- readFile "tasks.txt"
return (read content :: [Task])
else return []
-- Main program loop
main :: IO ()
main = do
initialTasks <- loadTasks
loop initialTasks
-- Command-line interface
loop :: [Task] -> IO ()
loop tasks = do
putStrLn "Commands: add <task>, view, remove <index>, done <index>, quit"
putStr "Enter command: "
hFlush stdout
command <- getLine
case words command of
("add":taskName) -> do
let updatedTasks = addTask (unwords taskName) tasks
saveTasks updatedTasks
loop updatedTasks
["view"] -> do
viewTasks tasks
loop tasks
("remove":indexStr) -> case reads (unwords indexStr) of
[(index, "")] -> do
let updatedTasks = removeTask index tasks
saveTasks updatedTasks
loop updatedTasks
_ -> putStrLn "Invalid index" >> loop tasks
("done":indexStr) -> case reads (unwords indexStr) of
[(index, "")] -> do
let updatedTasks = markTaskDone index tasks
saveTasks updatedTasks
loop updatedTasks
_ -> putStrLn "Invalid Index" >> loop tasks
["quit"] -> putStrLn "Goodbye!"
_ -> putStrLn "Unknown command" >> loop tasks
readFile :: FilePath -> IO String
[Hackage]确实是lazy,所以它承诺在需要内容时读取文件,但它不会(完全)读取文件本身。
seq
[Hackage] 在返回列表之前强制评估列表(的长度),从而将文件读取到末尾:
loadTasks :: IO [Task]
loadTasks = do
fileExists <- doesFileExist "tasks.txt"
if fileExists
then do
content <- readFile "tasks.txt"
length content `seq` return (read content :: [Task])
else return []
话虽这么说,我建议不要写入与读取的文件相同的文件。实际上,延迟读取通常是一种“想要的”效果:它减少了内存占用,并允许“流式传输”,其中源文件以块的形式读取和处理,因此文件永远不会完全加载到内存中。
大多数类 Unix 程序永远不会写入它们正在读取的文件,例如,通过使用 sort < frm.txt > /tmp/to.txt
,您在
/tmp/to.txt
中创建了一个排序变体,当成功时,您将
/tmp/to.txt
移动到 frm.txt
。这样,如果发生断电等情况,您始终至少拥有 或完整的源文件,
或已排序的文件。通过写入同一个文件,从而信任内存中的数据,如果断电,该文件可能不包含数据,或者只包含第一行,从而本质上“破坏”数据。