Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File 确保文件及时关闭_File_Haskell_Io_Strict - Fatal编程技术网

File 确保文件及时关闭

File 确保文件及时关闭,file,haskell,io,strict,File,Haskell,Io,Strict,我正在编写一个守护进程,它从一个小文件中读取一些内容,对其进行修改,然后将其写回同一个文件。我需要确保每个文件在读取后立即关闭,然后再尝试写入。我还需要确保每个文件在写入后立即关闭,因为我可能偶尔会立即再次读取 我已经研究过使用二进制strict而不是二进制,但是它似乎只提供严格的Get,而不是严格的Put。System.IO.Strict也存在同样的问题。通过阅读二进制严格文档,我不确定它是否真的解决了确保文件及时关闭的问题。最好的处理方法是什么?DeepSeq 下面是一个高度简化的示例,它将

我正在编写一个守护进程,它从一个小文件中读取一些内容,对其进行修改,然后将其写回同一个文件。我需要确保每个文件在读取后立即关闭,然后再尝试写入。我还需要确保每个文件在写入后立即关闭,因为我可能偶尔会立即再次读取

我已经研究过使用二进制strict而不是二进制,但是它似乎只提供严格的Get,而不是严格的Put。System.IO.Strict也存在同样的问题。通过阅读二进制严格文档,我不确定它是否真的解决了确保文件及时关闭的问题。最好的处理方法是什么?DeepSeq

下面是一个高度简化的示例,它将让您了解我的应用程序的结构。此示例以结束

*** Exception: test.dat: openBinaryFile: resource busy (file is locked) ***异常:test.dat:openBinaryFile:资源正忙(文件已锁定) 原因很明显

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
导入数据。二进制(二进制、编码、解码)
将Data.ByteString.Lazy作为B导入(readFile,writeFile)
导入Codec.Compression.GZip(压缩、解压缩)
encodeAndCompressFile::Binary a=>FilePath->a->IO()
encodeAndCompressFile f=B.writeFile f。压缩。编码
decodeAndDecompressFile::Binary a=>FilePath->IO a

decodeandecompressfile f=返回。解码解压缩=所有对文件的“放入”或“写入”都是严格的。
writeFile
的行为要求对所有Haskell数据进行评估,以便将其放在磁盘上

因此,您需要专注于对输入的懒读。在上面的例子中,你们都懒散地读取文件,然后懒散地解码它


相反,请尝试严格地读取文件(例如,使用strict ByTestRing),您会没事的。

考虑使用诸如、或之类的包。它们提供了惰性IO的许多好处(代码更简单,潜在的内存占用更小),而无需惰性IO。下面是一个使用and的示例:

导入数据。管道
导入Data.conductor.Binary(sinkFile、sourceFile)
导入Data.conductor.graines(sinkGet、sourcePut)
导入Data.conductor.Zlib(gzip,ungzip)
导入数据。序列化(序列化、获取、放置)
encodeAndCompressFile::序列化a=>FilePath->a->IO()
encodeAndCompressFile f v=
runResourceT$sourcePut(put v)$$gzip=$sinkFile f
decodeAndDecompressFile::序列化a=>FilePath->IO a
decodeandecompressfile f=do
返回值v
左错误->失败错误
main=do
设i=0::Int
encodeAndCompressFile“test.dat”i
多斯塔夫
doStuff=do

i使用导管等的一种替代方法是直接使用,这将允许您根据IO执行顺序明确控制何时关闭文件

您可以使用
openBinaryFile
,然后执行正常读取操作(可能是来自的操作)和
hClose
,或者使用
withBinaryFile
,自动关闭文件(但要小心)


正如Don所说,无论您使用什么方法,您可能都希望将其作为strict bytestring读取,然后使用将strict转换为lazy。

我很困惑。我想象
I
最初绑定到
doStuff
中的一个thunk,并且自从我们使用lazy
readFile
以来,实际上没有发生IO。然而,一旦我们
打印i
,这不就迫使对
i
进行评估,并完成所有IO吗?
解压了吗
没有读取所有文件,所以它是打开的吗?唐,你的解释帮助我理解了为什么我不需要严格版本的“put”或“write”;谢谢你。然而,我想我还需要找到一个严格版本的解压。最终我采用了Nathan的解决方案,因为我发现遵循代码更容易一些。无耻的插件:
管道
将在一周内推出快速、确定性和可组合的资源管理。@GabrielGonzalez非常棒。发布后Ping我,我会更新这个答案。完成了。我刚在电视上宣布的。
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