# 14.4. `xdrlib` — 编码与解码 XDR 数据

源代码: Lib/xdrlib.py

`xdrlib` 模块为外部数据表示标准提供支持，该标准的描述见 RFC 1014，由 Sun Microsystems, Inc. 在 1987 年 6 月撰写。 它支持该 RFC 中描述的大部分数据类型。

`xdrlib` 模块定义了两个类，一个用于将变量打包为 XDR 表示形式，另一个用于从 XDR 表示形式解包。 此外还有两个异常类。

class `xdrlib.``Packer`

  `Packer` 是用于将数据打包为 XDR 表示形式的类。 `Packer` 类的实例化不附带参数。

class `xdrlib.``Unpacker`(data)

  `Unpacker` 是用于相应地从字符串缓冲区解包 XDR 数据值的类。 输入缓冲区将作为 data 给出。

也參考

RFC 1014 - XDR: 外部数据表示标准

  这个 RFC 定义了最初编写此模块时 XDR 所用的数据编码格式。 显然它已被 RFC 1832 所淘汰。

RFC 1832 - XDR: 外部数据表示标准

  更新的 RFC，它提供了经修订的 XDR 定义。

## 14.4.1. Packer 对象

`Packer` 实例具有下列方法:

`Packer.``get_buffer`()

  将当前打包缓冲区以字符串的形式返回。

`Packer.``reset`()

  将打包缓冲区重置为空字符串。

总体来说，你可以通过调用适当的 `pack_type()` 方法来打包任何最常见的 XDR 数据类型。 每个方法都是接受单个参数，即要打包的值。 受支持的简单数据类型打包方法如下: `pack_uint()`, `pack_int()`, `pack_enum()`, `pack_bool()`, `pack_uhyper()` 以及 `pack_hyper()`。

`Packer.``pack_float`(value)

  打包单精度浮点数 value。

`Packer.``pack_double`(value)

  打包双精度浮点数 value。

以下方法支持打包字符串、字节串以及不透明数据。

`Packer.``pack_fstring`(n, s)

  打包固定长度字符串 s。 n 为字符串的长度，但它 不会 被打包进数据缓冲区。 如有必要字符串会以空字节串填充以保证 4 字节对齐。

`Packer.``pack_fopaque`(n, data)

  打包固定长度不透明数据流，类似于 `pack_fstring()`。

`Packer.``pack_string`(s)

  打包可变长度字符串 s。 先将字符串的长度打包为无符号整数，再用 `pack_fstring()` 来打包字符串数据。

`Packer.``pack_opaque`(data)

  打包可变长度不透明数据流，类似于 `pack_string()`。

`Packer.``pack_bytes`(bytes)

  打包可变长度字节流，类似于 `pack_string()`。

下列方法支持打包数组和列表:

`Packer.``pack_list`(list, pack_item)

  打包由同质条目构成的 list。 此方法适用于不确定长度的列表；即其长度无法在遍历整个列表之前获知。 对于列表中的每个条目，先打包一个无符号整数 `1`，再添加列表中数据的值。 pack_item 是在打包单个条目时要调用的函数。 在列表的末尾，会再打包一个无符号整数 `0`.

  例如，要打包一个整数列表，代码看起来会是这样:

      import xdrlib
      p = xdrlib.Packer()
      p.pack_list([1, 2, 3], p.pack_int)

`Packer.``pack_farray`(n, array, pack_item)

  打包由同质条目构成的固定长度列表 (array)。 n 为列表长度；它 不会 被打包到缓冲区，但是如果 `len(array)` 不等于 n 则会引发 `ValueError`。 如上所述，pack_item 是在打包每个元素时要使用的函数。

`Packer.``pack_array`(list, pack_item)

  打包由同质条目构成的可变长度 list。 先将列表的长度打包为无符号整数，再像上面的 `pack_farray()` 一样打包每个元素。

## 14.4.2. Unpacker 对象

`Unpacker` 类提供以下方法:

`Unpacker.``reset`(data)

  使用给定的 data 重置字符串缓冲区。

`Unpacker.``get_position`()

  返回数据缓冲区中的当前解包位置。

`Unpacker.``set_position`(position)

  将数据缓冲区的解包位置设为 position。 你应当小心使用 `get_position()` 和 `set_position()`。

`Unpacker.``get_buffer`()

  将当前解包数据缓冲区以字符串的形式返回。

`Unpacker.``done`()

  表明解包完成。 如果数据没有全部完成解包则会引发 `Error` 异常。

此外，每种可通过 `Packer` 打包的数据类型都可通过 `Unpacker` 来解包。 解包方法的形式为 `unpack_type()`，并且不接受任何参数。 该方法将返回解包后的对象。

`Unpacker.``unpack_float`()

  解包单精度浮点数。

`Unpacker.``unpack_double`()

  解包双精度浮点数，类似于 `unpack_float()`。

此外，以下方法可用来解包字符串、字节串以及不透明数据:

`Unpacker.``unpack_fstring`(n)

  解包并返回固定长度字符串。 n 为期望的字符数量。 会预设以空字节串填充以保证 4 字节对齐。

`Unpacker.``unpack_fopaque`(n)

  解包并返回固定长度数据流，类似于 `unpack_fstring()`。

`Unpacker.``unpack_string`()

  解包并返回可变长度字符串。 先将字符串的长度解包为无符号整数，再用 `unpack_fstring()` 来解包字符串数据。

`Unpacker.``unpack_opaque`()

  解包并返回可变长度不透明数据流，类似于 `unpack_string()`。

`Unpacker.``unpack_bytes`()

  解包并返回可变长度字节流，类似于 `unpack_string()`。

下列方法支持解包数组和列表:

`Unpacker.``unpack_list`(unpack_item)

  解包并返回同质条目的列表。 该列表每次解包一个元素，先解包一个无符号整数旗标。 如果旗标为 `1`，则解包条目并将其添加到列表。 旗标为 `0` 表明列表结束。 unpack_item 为在解包条目时调用的函数。

`Unpacker.``unpack_farray`(n, unpack_item)

  解包并（以列表形式）返回由同质条目构成的固定长度数组。 n 为期望的缓冲区内列表元素数量。 如上所述，unpack_item 是解包每个元素时要使用的函数。

`Unpacker.``unpack_array`(unpack_item)

  解包并返回由同质条目构成的可变长度 list。 先将列表的长度解包为无符号整数，再像上面的 `unpack_farray()` 一样解包每个元素。

## 14.4.3. 异常

此模块中的异常会表示为类实例代码:

exception `xdrlib.``Error`

  基本异常类。 `Error` 具有一个公共属性 `msg`，其中包含对错误的描述。

exception `xdrlib.``ConversionError`

  从 `Error` 所派生的类。 不包含额外的实例变量。

以下是一个应该如何捕获这些异常的示例:

    import xdrlib
    p = xdrlib.Packer()
    try:
        p.pack_double(8.01)
    except xdrlib.ConversionError as instance:
        print('packing the double failed:', instance.msg)