第十节:代码案例学习:解析二进制数据格式.pdfVIP

  • 9
  • 0
  • 约2.27万字
  • 约 19页
  • 2017-06-08 发布于湖北
  • 举报

第十节:代码案例学习:解析二进制数据格式.pdf

第⼗章:代码案例学习:解析⼆进制数据格式 第⼗章:代码案例学习:解析⼆进制数据格式 本章将会讨论⼀个常见任务:解析 (parsing )⼆进制⽂件。选这个任务有两个⽬的。 第⼀个确 是想谈谈解析过程,但更重要的⽬标是谈谈程序组织、重构和消除样板代 码 (boilerplate code :通常指不重要,但没它又不⾏的代码)。我们将会展⽰如何清 理冗余代码,并为第⼗四章讨论 Monad 做点准备。 我们将要⽤到的⽂件格式来⾃于 netpbm 库,它包含⼀组⽤来处理位图图像的程序及 ⽂件格式,它古⽼⽽令⼈尊敬。这种⽂件格式不但被⼴泛使⽤,⽽且还⾮常简单,虽 然解析过程也不是完全没有挑战。对我们⽽⾔最重要的是,netpbm ⽂件没有经过压 缩。 灰度⽂件 netpbm 的灰度⽂件格式名为 PGM (”portable grey map” )。事 上它不是⼀个格式, ⽽是两个:纯⽂本 (又名P2 )格式使⽤ ASCII 编码,⽽更常⽤的原始 (P5 )格式则采 ⽤⼆进制表⽰。 每种⽂件格式都包含头信息,头信息以⼀个“魔法”字符串开始,指出⽂件格式。纯⽂ 本格式是 P2 ,原始格式是 P5 。魔法字符串之后是空格,然后是三个数字:宽度、⾼ 度、图像的最⼤灰度值。这些数字⽤⼗进制 ASCII 数字表⽰,并⽤空格隔开。 最⼤灰度值之后便是图像数据了。在原始⽂件中,这是⼀串⼆进制值。纯⽂本⽂件 中,这些值是⽤空格隔开的⼗进制 ASCII 数字。 原始⽂件可包含多个图像,⼀个接⼀个,每个都有⾃⼰的头信息。纯⽂本⽂件只包含 ⼀个图像。 解析原始 PGM ⽂件 ⾸先我们来给原始 PGM ⽂件写解析函数。PGM 解析函数是⼀个纯函数。它不管获取 数据,只管解析。这是⼀种常见的 Haskell 编程⽅法。通过把数据的获取和处理分 开,我们可以很⽅便地控制从哪⾥获取数据。 我们⽤ ByteString 类型来存储灰度数据,因为它⽐较节省空间。由于 PGM ⽂件以 ASCII 字符串开头,⽂件内容又是⼆进制数据,我们同时载⼊两种形式的 ByteString 模块。 -- file: ch10/PNM .hs import qualified Data.ByteStrin .Lazy .Char8 as L8 import qualified Data.ByteStrin .Lazy as L import Data.Char (isSpace) 我们并不关⼼ ByteString 类型是惰性的还是严格的,因此我们随便选了惰性的版本。 我们⽤⼀个直⽩的数据类型来表⽰ PGM 图像。 -- file: ch10/PNM .hs data Greymap = Greymap { reyWidth :: Int , reyHei ht :: Int , reyMax :: Int , reyData :: L.ByteStrin } derivin (Eq) 通常来说,Haskell 的 S ow 例会⽣成数据的字符串表⽰,我们还可以⽤ read 读回 来。然⽽,对于⼀个位图图像⽂件来说,这可能会⽣成⼀个⾮常⼤的字符串,⽐如当 你对⼀张照⽚调⽤ s ow 的时候。基于这个原因,我们不准备让编译器⾃动为我们派 ⽣ S ow 例;我们会⾃⼰ 现,并刻意简化它。 -- file: ch10/PNM .hs instance Show Greymap where show (Greymap w h m _) = Greymap ++ show w ++ x ++ show h 我们的 S ow 例故意没打印位图数据,也就没必要写 Read 例了,因为我们⽆法从 s ow 的结果重构 Greymap 。 解析函数的类型显⽽易见。 -- file: ch10/PNM .hs parseP5 :: L.ByteStrin - Maybe (Greymap, L.ByteStrin ) 这个函数以⼀个 ByteString 为参数,如果解析成功的话,它返回⼀个被解析的 Greymap 值以及解析之后剩下的字符串,剩下的字符串以后会⽤到。 解析函数必须⼀点⼀点处理输⼊数据。⾸先,我们必须确认我们正在处理的是原始 PGM ⽂件;然后,我们处理头信息中的数字;最后我们处理位图数据。下⾯是是⼀ 种⽐较初级的 现⽅法,我们会在它的基础上不断改进。 -- file: ch10/P

文档评论(0)

1亿VIP精品文档

相关文档