我试图严格读取和解码二进制文件,这似乎在大多数时间都有效。但不幸的是在少数情况下我的计划失败,在Haskell中严格使用Binary解码文件的问题
“的字节数太少。无法读取字节位置1”
我猜二进制其解码功能认为没有数据可用, 但我知道有与只需重新运行该程序就可以正常工作。
我已经尝试了几种解决方案,但也不是能用来解决我的问题:(
withBinaryFile:
decodeFile' path = withBinaryFile path ReadMode doDecode where doDecode h = do c <- LBS.hGetContents h return $! decode c
阅读与它严格字节字符串解码整个文件:
decodeFile' path = decode . LBS.fromChunks . return <$> BS.readFile path
增加一些更严格的要求
decodeFile' path = fmap (decode . LBS.fromChunks . return) $! BS.readFile path
任何想法是怎么回事,如何解决这一问题?
谢谢!
编辑:我想我已经找到了我的问题。这不是严格阅读文件。我有一些主要从文件中读取的进程,但有时需要写入,这会先截断文件并添加新内容。因此,为了编写,我需要首先设置一个文件锁,当使用“Binary.encodeFile”(当我说流程我不是线程,但是运行同一程序的实例时)时,似乎没有这样做。
编辑终于有一段时间来解决我的问题,使用POSIX IO和文件锁定。从那以后我就没有更多的问题了。
为了防止有人对我当前的解决方案感兴趣,或者有人能够指出错误/问题,我会在此处发布我的解决方案。
安全编码文件:
safeEncodeFile path value = do
fd <- openFd path WriteOnly (Just 0o600) (defaultFileFlags {trunc = True})
waitToSetLock fd (WriteLock, AbsoluteSeek, 0, 0)
let cs = encode value
let outFn = LBS.foldrChunks (\c rest -> writeChunk fd c >> rest) (return()) cs
outFn
closeFd fd
where
writeChunk fd bs = unsafeUseAsCString bs $ \ptr ->
fdWriteBuf fd (castPtr ptr) (fromIntegral $ BS.length bs)
和解码文件:
safeDecodeFile def path = do
e <- doesFileExist path
if e
then do fd <- openFd path ReadOnly Nothing
(defaultFileFlags{nonBlock=True})
waitToSetLock fd (ReadLock, AbsoluteSeek, 0, 0)
c <- fdGetContents fd
let !v = decode $! c
return v
else return def
fdGetContents fd = lazyRead
where
lazyRead = unsafeInterleaveIO loop
loop = do blk <- readBlock fd
case blk of
Nothing -> return LBS.Empty
Just c -> do cs <- lazyRead
return (LBS.Chunk c cs)
readBlock fd = do buf <- mallocBytes 4096
readSize <- fdReadBuf fd buf 4096
if readSize == 0
then do free buf
closeFd fd
return Nothing
else do bs <- unsafePackCStringFinalizer buf
(fromIntegral readSize)
(free buf)
return $ Just bs
有了合格的进口严格懒字节串为:
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Internal as LBS
这不是一个严格的问题 - 例如,您的第二个解决方案可以保证读取所有数据。 您的二进制解析器本身可能存在一些问题吗? – 2010-07-25 17:47:02
考虑使用谷物而不是二进制。 – 2010-07-25 17:59:41
我只是存储和加载一个Trie for ByteStrings(包bytestring-trie)。 所以我对二进制比如get函数基本上是这样的: “GET = DO特里< - 获得;返回$ DATA(尺寸线索)特里” 这就是为什么我使用二进制,因为字节串,特里包已经有一个二元实例,我不认为谷物会是一个选择。 我的程序是从shell运行的,我想在某些情况下,两个实例可能同时访问该文件...所以也许这是由于文件锁定?是否有任何方法来设置和等待文件锁定被释放? – urso 2010-07-25 19:21:08