Я пытаюсь строго прочитать и декодировать двоичный файл, который, кажется, работает большую часть времени. Но, к сожалению, в некоторых случаях моя Программа не работает с
"слишком мало байтов. Ошибка чтения в позиции байта 1"
Я полагаю, что двоичная функция декодирования считает, что нет доступных данных,
но я знаю, что есть и просто перезапуск программы работает нормально.
Я пробовал несколько решений, но ни одно из них не смогло решить мою проблему: (
с использованием withBinaryFile:
decodeFile' path = withBinaryFile path ReadMode doDecode
where
doDecode h = do c <- LBS.hGetContents h
return $! decode c
чтение всего файла со строгой ByteString и декодирование из него:
decodeFile' path = decode . LBS.fromChunks . return <$> BS.readFile path
добавив немного строгости
decodeFile' path = fmap (decode . LBS.fromChunks . return) $! BS.readFile path
Есть идеи, что здесь происходит и как решить проблему?
Спасибо!
РЕДАКТИРОВАТЬ: Я думаю, что я понял свою проблему. Речь идет не о строгом чтении файла. У меня есть ряд процессов, в основном читающих из файла, но время от времени нужно писать в него, который сначала усекает файл, а затем добавляет новое содержимое. Поэтому для записи мне нужно сначала установить блокировку файла, что, кажется, не делается при использовании «Binary.encodeFile» (когда я говорю «процесс», я имею в виду не потоки, а реальные экземпляры той же самой программы, которая выполняется). 1032 *
РЕДАКТИРОВАТЬ Наконец-то было время решить мою проблему с помощью POSIX IO и File Locks. У меня больше не было проблем с тех пор.
На всякий случай, если кто-то заинтересован в моем текущем решении или, возможно, кто-то сможет указать на ошибки / проблемы, я опубликую свое решение здесь.
Безопасное кодирование в файл:
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