使用Python读取二进制Plist文件

3

我目前使用Plistlib模块来读取Plist文件,但在处理二进制Plist文件时遇到了问题。

我希望将数据读入字符串中以供分析/打印等。 我想知道是否有一种不使用plutil函数并将二进制文件转换为XML的方法来读取二进制Plist文件?

提前感谢您的帮助和时间。


1
可能是Python二进制plist模块的重复。 - Janne Karila
谢谢Janne,我看过这篇文章,但我希望有人知道如何在不安装单独模块的情况下执行上述操作,并只使用Python中可用的预安装模块。 - Zeki Turedi
默认模块plistlib不支持二进制plist文件。您最好选择“biplist”或其他第三方模块。 - Gentle Y
5个回答

6

虽然您没有指定使用plutil,但是对于其他人来说,使用它可能是有用的,因为它已经预装在Mac上:

import json
from subprocess import Popen, PIPE

def plist_to_dictionary(filename):
    "Pipe the binary plist through plutil and parse the JSON output"
    with open(filename, "rb") as f:
        content = f.read()
    args = ["plutil", "-convert", "json", "-o", "-", "--", "-"]
    p = Popen(args, stdin=PIPE, stdout=PIPE)
    out, err = p.communicate(content)
    return json.loads(out)

print plist_to_dictionary(path_to_plist_file)

1
如果您向此函数提供足够大的输入,它将在 p.stdin.write(content) 处卡住。请阅读文档。 - youfu

3
我可能晚了10年才回答这个问题,但是对于任何正在寻找它的人,plistlib 就是你要找的。

看起来这个模块只在Python 3.4中有二进制支持,而当问题被提出时,这个版本还不存在。 - undefined
@TimTisdall 这正是为什么我加上了“我可能晚了10年才回答”的原因。我回答是为了给今天寻求方向的人节省一些时间,而不是回答原始问题。 - undefined
你晚了7年...3.4版本在2014年发布,而你的回答是在2021年。;) 我点赞了,因为这绝对是现在问题的答案,我只是在评论中补充了一些背景信息,因为楼主说在2012年使用plistlib无法处理二进制文件。 - undefined

3

1

0

你可以查看CFBinaryPList.c源文件来了解它是如何在C中实现的。

根据这个文件,它的格式是这样的:

HEADER
    magic number ("bplist")
    file format version (currently "0?")

OBJECT TABLE
    variable-sized objects

    Object Formats (marker byte followed by additional info in some cases)
    null    0000 0000           // null object [v"1?"+ only]
    bool    0000 1000           // false
    bool    0000 1001           // true
    url 0000 1100   string      // URL with no base URL, recursive encoding of URL string [v"1?"+ only]
    url 0000 1101   base string // URL with base URL, recursive encoding of base URL, then recursive encoding of URL string [v"1?"+ only]
    uuid    0000 1110           // 16-byte UUID [v"1?"+ only]
    fill    0000 1111           // fill byte
    int 0001 0nnn   ...     // # of bytes is 2^nnn, big-endian bytes
    real    0010 0nnn   ...     // # of bytes is 2^nnn, big-endian bytes
    date    0011 0011   ...     // 8 byte float follows, big-endian bytes
    data    0100 nnnn   [int]   ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes
    string  0101 nnnn   [int]   ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
    string  0110 nnnn   [int]   ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t
    string  0111 nnnn   [int]   ... // UTF8 string, nnnn is # of chars, else 1111 then int count, then bytes [v"1?"+ only]
    uid 1000 nnnn   ...     // nnnn+1 is # of bytes
        1001 xxxx           // unused
    array   1010 nnnn   [int]   objref* // nnnn is count, unless '1111', then int count follows
    ordset  1011 nnnn   [int]   objref* // nnnn is count, unless '1111', then int count follows [v"1?"+ only]
    set 1100 nnnn   [int]   objref* // nnnn is count, unless '1111', then int count follows [v"1?"+ only]
    dict    1101 nnnn   [int]   keyref* objref* // nnnn is count, unless '1111', then int count follows
        1110 xxxx           // unused
        1111 xxxx           // unused

OFFSET TABLE
    list of ints, byte size of which is given in trailer
    -- these are the byte offsets into the file
    -- number of these is in the trailer

TRAILER
    byte size of offset ints in offset table
    byte size of object refs in arrays and dicts
    number of offsets in offset table (also is number of objects)
    element # in offset table which is top level object
    offset table offset

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接