我希望是否有人提供完整的工作代码,允许在 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 用于实际的输入/输出部分。看看它提供的 hGethPut 函数。 (或者,如果您只需要严格的线性访问,您可以尝试使用惰性 I/O,但很容易出错。)

当然,一个字节串只是一个字节数组;您的下一个问题是将这些字节解释为字符/整数/ double 数/它们应该是的任何其他内容。有几个包,但 Data.Binary 似乎是最主流的一个。
binary 的文档似乎想引导您使用 Binary 类,您可以在其中编写代码来序列化和反序列化整个对象。但是您可以使用 Data.Binary.GetData.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/

10-13 02:57