9

小さなファイルから何かを読み取り、それを変更して、同じファイルに書き戻すデーモンを書いています。書き込んだ後、書き込もうとする前に、各ファイルがすぐに閉じられることを確認する必要があります。また、ファイルをすぐに再度読み取る場合があるため、書き込み後すぐに各ファイルが閉じていることを確認する必要もあります。

バイナリの代わりにbinary-strictを使用することを検討しましたが、厳密なGetのみを提供し、厳密なPutは提供しないようです。System.IO.Strictと同じ問題。そして、binary-strictのドキュメントを読んだことから、ファイルがすぐに閉じられるようにするという私の問題が本当に解決されるかどうかはわかりません。これを処理するための最良の方法は何ですか?DeepSeq?

これは、私のアプリケーションの構造のアイデアを与える非常に単純化された例です。この例はで終了します

***例外: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
4

3 に答える 3

11

ファイルへのすべての「書き込み」または「書き込み」は厳密です。この行為は、writeFileすべてのHaskellデータをディスクに配置するために評価することを要求します。

したがって、集中する必要があるのは、入力の遅延読み取りです。上記の例では、ファイルを怠惰に読み取り、次にそれを怠惰にデコードします。

代わりに、ファイルを厳密に(たとえば、厳密なバイト文字列で)読み取ってみてください。そうすれば問題ありません。

于 2012-05-09T14:55:31.640 に答える
7

コンジットパイプイテラティー列挙子などのパッケージの使用を検討してください。それらは、レイジーIOなしでレイジーIOの多くの利点(より単純なコード、潜在的に小さなメモリフットプリント)を提供します。これは、コンジットシリアルを使用した例です。

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
于 2012-05-09T20:08:05.333 に答える
2

コンジットなどを使用する代わりに。を使用するだけSystem.IOで、IOの実行順序に関してファイルを閉じるタイミングを明示的に制御できます。

openBinaryFileその後に通常の読み取り操作(おそらくからの操作Data.ByteString)を使用し、それが終了hCloseしたら、または、ファイルを自動的に閉じます(ただし、この種の問題にwithBinaryFile注意してください)。

Donが言ったように、使用する方法が何であれ、おそらくstrictバイト文字列として読み取り、後でstrictを。でレイジーに変換する必要がありfromChunksます。

于 2012-05-11T01:17:06.400 に答える