filenode - 使用 PyTables 模拟文件系统

filenode - 使用 PyTables 模拟文件系统#

什么是 filenode#

filenode 是一个模块,使您能够创建 PyTables 数据库节点,这些节点可以像 Python 中的常规打开文件一样使用。换句话说,您可以将文件存储在 PyTables 数据库中,并像在 Python 中处理任何其他文件一样读取和写入它。与 PyTables 分层数据库组织结合使用时,您可以将数据库转换为开放、可扩展、高效、高容量、便携且丰富的元数据文件系统,用于与其他系统(包括备份目的)进行数据交换。

filenode 的主要功能中,可以列出:

  • 开放:由于它依赖于 PyTables,而 PyTables 又依赖于 HDF5(参见 HDGG1),这是来自 NCSA 的标准分层数据格式。

  • 可扩展:您可以定义新的节点类型,它们的实例将由 PyTables 应用程序安全地保存(就像普通组、叶和属性一样),这些应用程序对它们的类型一无所知。此外,节点的可能属性集不是固定的,因此您可以定义自己的节点属性。

  • 高效:由于 PyTables 在处理大量数据方面的极端效率,filenode 可以利用 PyTables 的实时压缩和解压缩数据。

  • 高容量:由于 PyTables 和 HDF5 设计用于大规模数据存储(即使平台不支持,它们也使用 64 位寻址)。

  • 便携:由于 HDF5 格式具有架构中立的设计,并且 HDF5 库和 PyTables 已知在各种平台上运行。此外,PyTables 数据库适合单个文件,这对传输没有问题。

  • 丰富的元数据:由于 PyTables 可以为每个数据库节点存储任意键值对(甚至是 Python 对象!)。元数据可能包括作者、关键字、MIME 类型和编码、所有权信息、访问控制列表(ACL)、解码函数以及您能想象到的任何内容!

查找 filenode 节点#

filenode 节点可以通过它们具有值为‘file’的 NODE_TYPE 系统属性来识别。建议您使用 tables.File 类的 tables.File.get_node_attr() 方法来获取 NODE_TYPE 属性,而不考虑节点的性质(组或叶),因此您无需关心。

filenode - 在 PyTables 内部模拟文件

filenode 模块是 PyTables 的 nodes 子包的一部分。导入模块的推荐方式是:

from tables.nodes import filenode

然而,filenode 导出的符号非常少,因此您可以为交互式使用导入 *。事实上,您最可能只使用 tables.nodes.filenode.NodeType 常量以及 tables.nodes.filenode.new_node()tables.nodes.filenode.open_node() 调用。

tables.nodes.filenode.NodeType 常量包含节点文件的 NODE_TYPE 系统属性应包含的值(如我们所见,为‘file’)。虽然这不太可能改变,但您应尽可能使用 tables.nodes.filenode.NodeType,而不是字面量‘file’。

tables.nodes.filenode.new_node()tables.nodes.filenode.open_node() 相当于 Python 的 file() 调用(别名 open()),用于普通文件。它们的参数与 file() 不同,但这是您在使用节点文件和普通文件时唯一会注意到差异的地方。

对于这个小教程,假设有以写入模式打开的 PyTables 数据库。此外,如果您在输入句子时有些懒惰,我们将解释的代码包含在 examples/filenodes1.py 文件中。

您可以使用以下句子创建全新的文件:

from pathlib import Path

temp_dir = Path(".temp")
temp_dir.mkdir(exist_ok=True)
import tables
h5file = tables.open_file(temp_dir/'fnode.h5', 'w')

创建新文件节点#

创建新文件节点是通过 tables.nodes.filenode.new_node() 调用实现的。您必须告诉它在哪个 PyTables 文件中创建它,在 PyTables 层次结构中的哪个位置创建节点以及它的名称是什么。PyTables 文件是 tables.nodes.filenode.new_node() 的第一个参数;它也将被称为“主机 PyTables 文件”。其他两个参数必须分别作为关键字参数 wherename 给出。作为调用的结果,返回全新的可追加和可读的文件节点对象。

因此,让我们在之前打开的 h5file PyTables 文件中创建名为‘fnode_test’的新节点文件,并将其放置在数据库层次结构的根部。这是该命令:

fnode = filenode.new_node(h5file, where='/', name='fnode_test')

基本上,这就是你创建文件节点所需的全部内容。很简单,不是吗?从那一刻起,你就可以像使用任何已打开的 Python 文件一样使用 fnode (例如,你可以写入数据、读取数据、文本行等)。

tables.nodes.filenode.new_node() 接受一些额外的关键字参数。你可以通过 title 参数为你的文档设定标题。你可以利用 PyTables 的压缩功能,通过 filters 参数实现。如果你事先知道文件的大小,你可以通过expectedsize参数提供最终的文件大小(以字节为单位),这样 PyTables 库就能优化数据访问。

tables.nodes.filenode.new_node() 将在被告知的位置创建 PyTables 节点。为了证明这一点,将尝试从新创建的节点中获取 NODE_TYPE 属性:

print(h5file.get_node_attr('/fnode_test', 'NODE_TYPE'))
file

使用文件节点#

如上所述,您可以将新节点文件用作任何其他打开的文件。让我们尝试写入一些文本并读取它:

print("This is a test text line.", file=fnode)
print("And this is another one.", file=fnode)
print(file=fnode)
fnode.write("Of course, file methods can also be used.")

fnode.seek(0)  # Go back to the beginning of file.

for line in fnode:
    print(repr(line))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 print("This is a test text line.", file=fnode)
      2 print("And this is another one.", file=fnode)
      3 print(file=fnode)

File /media/pc/data/lxw/envs/anaconda3a/envs/ai/lib/python3.12/site-packages/tables/nodes/filenode.py:346, in RawPyTablesIO.write(self, b)
    343 self._checkWritable()
    345 if isinstance(b, str):
--> 346     raise TypeError("can't write str to binary stream")
    348 n = len(b)
    349 if n == 0:

TypeError: can't write str to binary stream

这在 Unix 系统上运行,因此换行符表示为"n"。事实上,您可以通过将其 line_separator 属性设置为您想要的任何字符串来覆盖文件的行分隔符。

在使用文件节点时,您应在关闭 PyTables 主机文件之前关闭它。由于 PyTables 的工作方式,您的数据不会处于风险之中,但您在关闭主机文件后执行的每个操作都会失败并引发 ValueError。要关闭文件节点,只需删除它或调用其 close() 方法:

fnode.close()
print(fnode.closed)