我試圖嚴格讀取和解碼二進制文件,這似乎在大多數時間都有效。但不幸的是在少數情況下我的計劃失敗,在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