我希望是否有人提供完整的工作代码,允许在 Haskell 中执行以下操作:
我很困惑,因为我几乎找不到关于此的文档。 Data.Binary、ByteString、Word8 等等,它只会增加困惑。对于 C/C++ 中的此类问题,有非常直接的解决方案。获取所需大小的数组(例如无符号整数),并使用读/写库调用并完成它。在 Haskell 中,这似乎并不容易,至少对我而言。
如果您的解决方案使用主流 Haskell(> GHC 7.10)提供的最佳标准包而不是一些晦涩/过时的包,我将不胜感激。
我从这些页面上读到
https://wiki.haskell.org/Binary_IO
https://wiki.haskell.org/Dealing_with_binary_data
最佳答案
如果您正在执行二进制 I/O,您几乎肯定需要 ByteString
用于实际的输入/输出部分。看看它提供的 hGet
和 hPut
函数。 (或者,如果您只需要严格的线性访问,您可以尝试使用惰性 I/O,但很容易出错。)
当然,一个字节串只是一个字节数组;您的下一个问题是将这些字节解释为字符/整数/ double 数/它们应该是的任何其他内容。有几个包,但 Data.Binary
似乎是最主流的一个。binary
的文档似乎想引导您使用 Binary
类,您可以在其中编写代码来序列化和反序列化整个对象。但是您可以使用 Data.Binary.Get
和 Data.Binary.Put
中的函数来处理单个项目。在那里你会找到诸如 getWord32be
(get Word32
big-endian) 之类的函数。
我现在没有时间写一个工作代码示例,但基本上看看我上面提到的函数并忽略其他所有内容,你应该会有一些想法。
现在使用工作代码:
module Main where
import Data.Word
import qualified Data.ByteString.Lazy as BIN
import Data.Binary.Get
import Data.Binary.Put
import Control.Monad
import System.IO
main = do
h_in <- openFile "Foo.bin" ReadMode
h_out <- openFile "Bar.bin" WriteMode
replicateM 1000 (process_chunk h_in h_out)
hClose h_in
hClose h_out
chunk_size = 1000
int_size = 4
process_chunk h_in h_out = do
bin1 <- BIN.hGet h_in chunk_size
let ints1 = runGet (replicateM (chunk_size `div` int_size) getWord32le) bin1
let ints2 = map (\ x -> if x < 1000 then 2*x else x) ints1
let bin2 = runPut (mapM_ putWord32le ints2)
BIN.hPut h_out bin2
我相信,这可以满足您的要求。它读取 1000 块
chunk_size
字节,将每个块转换为 Word32
列表(因此它一次只有 chunk_size / 4
整数在内存中),执行您指定的计算,然后再次将结果写回。显然,如果您“真正地”执行此操作,则需要进行 EOF 检查等。
关于Haskell 读/写二进制文件完整的工作示例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32253948/