提问人:Rehpotsirhc 提问时间:2/27/2023 更新时间:2/27/2023 访问量:244
在 Haskell 中删除文件的最后一行
Deleting the last line of a file in Haskell
问:
我是 Haskell 的初学者,正在尝试在 Haskell 中重写我的一个 shell 脚本作为测试。我试图完成的一件事是删除文件的最后一行并读取其值。
我尝试使用 然后,但我不能,因为它很懒惰。
我能够使用以下代码让它工作:readFile
writeFile
import Data.List
import qualified Data.ByteString.Char8 as B
import qualified Data.Text as T
import qualified Data.Text.Encoding as TL
erase filename = do
contents <- B.readFile filename
let array = map (T.unpack . TL.decodeUtf8) (B.lines contents)
B.writeFile filename $ B.pack (intercalate "\n" (init array))
print $ last array
这会将文件的行转换为列表,然后写入不带最后一行的文件。它正在使用 ByteString,因此它不会懒惰。但是,我认为这种方式非常冗长,而且做得很奇怪。是否有某些功能可以从文件中删除一行,或者如何改进此代码?
答:
3赞
willeM_ Van Onsem
2/27/2023
#1
我建议不要写入同一个文件:大多数 linux 命令通常总是写入不同的文件,然后可以选择将目标文件移动到原始文件上。例如,如果排序,则始终至少具有原始文件或结果文件。
我们可以实现一个 helper 函数来获取第一行和最后一行的内容:
safeUnsnoc :: a -> [a] -> ([a], a)
safeUnsnoc d = go
where go [] = ([], d)
go [x] = ([], x)
go (x:xs) = (x:a, b) where ~(a, b) = go xs
这通常更好:它将避免在列表中枚举两次,因此这可能更保守内存。
然后我们可以从文件中读取,将文件存储在临时文件中,然后进行文件移动:
import System.Directory(renameFile)
import System.IO.Temp(writeSystemTempFile)
erase filename = do
(content, lastLine) <- safeUnsnoc "" . lines <$> readFile filename
tmp <- writeSystemTempFile "temp-init" (unlines content)
renameFile tmp filename
putStrLn lastLine
评论