2007-07-11

 

Python Cookbook 2.8 使用随机方式修改

需求:

要从一个大的二进制文件中读取 一块数据,修改完成后,要写回文件.

讨论:

打开文件,做必要的偏移计算,读取数据,处理完后,重新定位到数据偏移处,写入数据即可.看代码吧,比说的更清楚一些:

import struct
format_string = '8l'                # e.g., say a record is 8 4-byte integers
thefile = open('somebinfile', 'r+b')
record_size = struct.calcsize(format_string)
thefile.seek(record_size * record_number)
buffer = thefile.read(record_size)
fields = list(struct.unpack(format_string, buffer))
# Perform computations, suitably modifying fields, then:
buffer = struct.pack(format_string, *fields)
thefile.seek(record_size * record_number)
thefile.write(buffer)
thefile.close( )

这种方式只有在二进制文件的数据块是固定大小的时候适用,对于一般的文本文件不适用,另外, 数据库的大小要和struct中定义的一样.代码中的struct的典型定义'8l',表示每一个字段是8个4字节的整数构成,它们都是有符号整数类型,被转换为Python的int型数据.这样,上面的代码中fields表示了8个整数为单位的列表.需要注意的是unpack返回的是一个元组,而元组是不可修改的,所以要将它重新绑定为一个列表,因为列表是可以修改的.但要注意的是,不要修改列表的大小,因为如果你要用struct.pack写回的时候 ,会抛出异常.同样,本节的方法也不适用于文件中数据块大小不固定的情况.
当再次定位文件指针的时候,可以不使用seek(record_size * record_number),而使用反向偏移定位:

thefile.seek(-record_size, 1)

其中第二个参数1表示从文件的当前位置开始定位,由于第一个参数是负值, 所以是向前定位了.seek默认是从文件的起始位置开始定位,当然你也可以显示的将第二个参数设置为0.
当你调用第一个seek之前,不必再次调用open打开文件,同样,也不用在调用完write方法后立刻close它.当你正确打开了文件对象(二进制更新模式,而不是文本模式),你可以任意次数的更新文件,最后再关闭.
文件需要以更新模式打开(同时支持读和写),这就是'r+b'的含义:为读和写操作打开文件,并且不做任何隐含的转换,因为是二进制模式的.('b'在Unix和类unix系统上是可选的,不过还是建议加上,当然,在windows系统是,是必须的),如果你只是想创建一个草稿文件,可是仍要做一些读写处理,可以使用'w+b' 做为open的第二个参数.当然,我从来没有见过这么奇怪的需求.二进制文件一般都是先被创建(使用'wb'参数,写数据,然后关闭),再用'r+b'参数打开处理.
当然,虽然本节提供的方法只适用于固定数据块大小的二进制文件,也可以适用于更高级的情况:有一个索引文件表示块的大小和位置,这种通过索引文件访问的技术已经不是什么新技术了,可是它还是非常重要的.在今天,虽然人们处理的情况大多数是数据库,文本文件(还包括html,xml等),还有偶尔的固定块大小的二进制文件, 也不能排出遇到使用索引文件的可能性.如果遇到这样的情况,处理的方法和本节是非常类似的,只是块大小和偏移位置不是计算的,而是从索引文件中读取的.

相关说明:

seek(...)
    seek(offset[, whence]) -> None.  Move to new file position.
   
    Argument offset is a byte count.  Optional argument whence defaults to
    0 (offset from start of file, offset should be >= 0); other values are 1
    (move relative to current position, positive or negative), and 2 (move
    relative to end of file, usually negative, although many platforms allow
    seeking beyond the end of a file).  If the file is opened in text mode,
    only offsets returned by tell() are legal.  Use of other offsets causes
    undefined behavior.
    Note that not all file objects are seekable.

Comments: 发表评论



<< Home

This page is powered by Blogger. Isn't yours?