我希望如果有人提供了一个完整的工作代码,允许在Haskell中执行以下操作:
读取一个非常大的32位序列(超过10亿个元素) 从二进制文件到适当容器的int值(例如 当然不是列表,因为性能问题)和每个数字加倍 如果它小于1000(十进制)然后写入结果的32位 int值到另一个二进制文件。我可能不想读全文 内存中二进制文件的内容一次。我想读一个 之前的大块。
我很困惑因为我找不到关于此的文档。 Data.Binary,ByteString,Word8等等,它只是增加了混乱。对C / C ++中的这些问题有非常直接的解决方案。获取所需大小的数组(例如unsigned int),并使用读/写库调用并完成它。在Haskell中,它似乎并不那么容易,至少对我而言。
如果您的解决方案使用主流Haskell(> GHC 7.10)提供的最佳标准软件包而不是某些模糊/过时的软件包,我将不胜感激。
我从这些页面阅读
答案 0 :(得分:4)
如果您正在进行二进制 I / O,那么您几乎肯定希望ByteString
用于实际的输入/输出部分。查看它提供的hGet
和hPut
函数。 (或者,如果您只需要严格的线性访问权限,则可以尝试使用惰性I / O,但很容易出错。)
当然,字节字符串只是一个字节数组;你的下一个问题是将这些字节解释为字符/整数/双精度/它们应该是的其他任何东西。有几个包,但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
个整数),是否指定了计算,并写入结果再次退出。
显然,如果你做了这个&#34;对于真实的&#34;你想要EOF检查等等。
答案 1 :(得分:0)
这是一个从stdin
:
import System.IO
loop = do b <- hIsEOF stdin
if b then return ()
else do str <- hGetLine stdin
let str' = ...process str...
hPutStrLn stdout str'
现在只需用{4}字节等替换hGetLine
以下是Data.ByteString
的I / O部分:
https://hackage.haskell.org/package/bytestring-0.10.6.0/docs/Data-ByteString.html#g:29