我正在编写一个守护程序,它从一个小文件读取内容,修改它,然后将其写回同一个文件。在尝试写入之前,我需要确保每个文件在阅读后立即关闭。我还需要确保每个文件在写完后立即关闭,因为我可能偶尔会立即再次阅读它。
我已经研究过使用二进制严格而不是二进制,但似乎只提供严格的Get,而不是严格的Put。与System.IO.Strict相同的问题。从阅读二进制严格的文档,我不确定它真的解决了我确保文件被迅速关闭的问题。处理这个问题的最佳方法是什么? DeepSeq?
这是一个高度简化的示例,可以让您了解我的应用程序的结构。此示例以
结尾*** Exception: test.dat: openBinaryFile: resource busy (file is locked)
原因很明显。
import Data.Binary ( Binary, encode, decode )
import Data.ByteString.Lazy as B ( readFile, writeFile )
import Codec.Compression.GZip ( compress, decompress )
encodeAndCompressFile :: Binary a => FilePath -> a -> IO ()
encodeAndCompressFile f = B.writeFile f . compress . encode
decodeAndDecompressFile :: Binary a => FilePath -> IO a
decodeAndDecompressFile f = return . decode . decompress =<< B.readFile f
main = do
let i = 0 :: Int
encodeAndCompressFile "test.dat" i
doStuff
doStuff = do
i <- decodeAndDecompressFile "test.dat" :: IO Int
print i
encodeAndCompressFile "test.dat" (i+1)
doStuff
答案 0 :(得分:11)
对文件的所有“放置”或“写入”都是严格的。 writeFile
的行为要求评估所有Haskell数据,以便将其放在磁盘上。
所以你需要关注的是输入的懒惰阅读。在上面的例子中,你懒得读取文件,然后懒洋洋地解码它。
相反,请尝试严格阅读文件(例如使用严格的字节串),你会没事的。
答案 1 :(得分:7)
考虑使用conduit,pipes,iteratee或enumerator等软件包。它们提供了懒惰IO(更简单的代码,可能更小的内存占用)的许多好处,而没有惰性IO。以下是使用conduit和cereal的示例:
import Data.Conduit
import Data.Conduit.Binary (sinkFile, sourceFile)
import Data.Conduit.Cereal (sinkGet, sourcePut)
import Data.Conduit.Zlib (gzip, ungzip)
import Data.Serialize (Serialize, get, put)
encodeAndCompressFile :: Serialize a => FilePath -> a -> IO ()
encodeAndCompressFile f v =
runResourceT $ sourcePut (put v) $$ gzip =$ sinkFile f
decodeAndDecompressFile :: Serialize a => FilePath -> IO a
decodeAndDecompressFile f = do
val <- runResourceT $ sourceFile f $$ ungzip =$ sinkGet get
case val of
Right v -> return v
Left err -> fail err
main = do
let i = 0 :: Int
encodeAndCompressFile "test.dat" i
doStuff
doStuff = do
i <- decodeAndDecompressFile "test.dat" :: IO Int
print i
encodeAndCompressFile "test.dat" (i+1)
doStuff
答案 2 :(得分:2)
使用导管等的替代方案。将只使用System.IO
,这将允许您明确控制文件何时关闭IO执行顺序。
您可以使用openBinaryFile
,然后使用正常阅读操作(可能是Data.ByteString
}和hClose
完成后的操作,或withBinaryFile
,关闭文件自动(但要注意this sort of problem)。
无论你使用哪种方法,正如唐所说,你可能想要读作严格的字节串,然后用fromChunks
将严格转换为懒惰。