7.6 练习
第一个练习是创建一个比本章展示的更简单的二进制记录文件模块——其记录大小与用户指定的恰好一样。第二个练习是使用新的二进制记录文件模块对BikeStock模块进行修改。第三个练习要求从头开始创建一个程序——其中的文件处理部分是非常直截了当的,但某些输出格式有一定难度。
1.创建一个新的、更简单的BinaryRecordFile模块版本——其中不使用状态字节。对这一版本而言,用户指定的记录大小就是记录的实际大小。如果要添加新记录,就必须使用一个新的append()方法,该方法只是简单地将文件指针移动到文件末尾,并写入待添加的记录。__setitem__()方法应该只允许替换现存的记录,为此,一种简单的方法是使用__seek_to_index()方法。由于不再使用状态字节,因此__getitem__()消减到只有3行代码。__delitem__()方法需要完全重写,因为该方法必须移动所有相关的记录,以便消除文件中存在的差距,这仅需要大概6行代码即可完成,但确实也需要一些设计与衡量。undelete()方法必须移除,因为新实现的模块不支持这种操作,compact()方法与inplace_compact()方法也必须被移除,同样是因为不再需要。
总体而言,与原始版本相比,新版本需要添加或修改不到20行代码,并删除至少60行代码(doctests除外)。BinaryRecordFile_ans.py提供了针对该练习的解决方案。
2.在确定更简单的BinaryRecordFile类可以正常工作后,复制BikeStock.py文件并对其进行修改,使其可以与BinaryRecordFile类共同工作。这只需要修改少数几行代码,BikeStock_ans.py文件提供了相应的解决方案。
3.对二进制格式进行调试可能是比较困难的,但使用工具对二进制文件内容进行转储将有助于分析。创建一个程序,使其有如下的控制台帮助文本:
Usage: xdump.py [options] file1 [file2 [... fileN]]
Options:
-h, --help show this help message and exit
-b BLOCKSIZE, --blocksize=BLOCKSIZE
block size (8..80) [default: 16]
-d, --decimal decimal block numbers [default: hexadecimal]
-e ENCODING, --encoding=ENCODING
encoding (ASCII..UTF-32) [default: UTF-8]
如果有一个BinaryRecordFile,其中存储记录的格式为“<i10s”(little-endian,4字节有符号整数,10字节字符串),使用这一程序,通过将块大小设置为与记录大小匹配(15字节,包括状态字节),可以获取文件中内容的清晰影像,比如:
xdump.py -b15 test.dat
Block Bytes UTF-8 characters
-------- --------------------------------- ----------
00000000 02000000 00416C70 68610000 000000 .....Alpha.....
00000001 01140000 00427261 766F0000 000000 .....Bravo.....
00000002 02280000 00436861 726C6965 000000 .(...Charlie...
00000003 023C0000 0044656C 74610000 000000 .<...Delta.....
每个字节都使用一个两个数字表示的十六进制数,其中每组4字节之间(或每组8个十六进制数字之间)的空格的作用只是为了提高可读性。这里,我们可以看到,第二条记录(“Bravo”)已经被删除,因为其状态字节为0x01,而不是用于指示非空白其未删除记录的0x02。
使用optparse模块来处理命令行选项(通过指定某选项的类型,可以使optparse处理字符串到整数的转换)。要使标题对准任意给定的块大小并正确对准最后一块的字符,可能是非常棘手的,因此,要确保对不同块大小进行了测试(比如8、9、10…40)。并且,不要忘记对不同长度的文件,最后一块可能是很短的。如实例中所展示的,可以使用句点来表示不可打印的字符。
该程序可以使用不到70行代码完成,包括两个函数,xdump.py提供了相应的解决方案。