Python:使用 Kaitai Struct 读取 ID3v1 标签

Posted

技术标签:

【中文标题】Python:使用 Kaitai Struct 读取 ID3v1 标签【英文标题】:Python: reading ID3v1 tag with Kaitai Struct 【发布时间】:2016-08-07 19:55:21 【问题描述】:

我正在尝试让 Kaitai Struct 解析 MP3 的 ID3v1 标签格式。根据standard,它是一个固定格式结构,位于某个偏移量处——但诀窍是这个偏移量不是从文件开头计算的,而是从文件末尾计算的。

这是标签的基本.ksy 轮廓,我认为它不应该真正改变:

meta:
  id: id3v1
types:
  id3v1_tag:
    seq:
      - id: magic
        contents: 'TAG'
      - id: title
        size: 30
      - id: artist
        size: 30
      - id: album
        size: 30
      - id: year
        size: 4
      - id: comment
        size: 30
      - id: genre
        type: u1

这是我关于如何从 128 个字节到文件末尾读取它的幼稚想法:

instances:
  tag:
    pos: -128
    type: id3v1_tag

我尝试使用一个简单的 Python 测试脚本:

#!/usr/bin/env python

from id3v1 import *

f = Id3v1.from_file('some_file_with_id3.mp3')
print(f.tag)

但是,它似乎将负数直接传递到 Python 的 File 对象 seek() 中,因此失败了:

Traceback(最近一次调用最后一次):文件“try-id3.py”,第 6 行,在 打印(f.id3v1_tag)文件“id3v1_1.py”,第 171 行,在 id3v1_tag 中 self._io.seek(-128) 文件“kaitaistruct.py”,第 29 行,在搜索中 self._io.seek(n) IOError: [Errno 22] 无效参数

在其他一些同样疯狂的想法之后,我找到了一种解决方法:我可以省略 .ksy 中的任何 pos 参数,然后手动寻找脚本中的正确位置:

f = Id3v1.from_file('some_file_with_id3.mp3')
f._io.seek(-128, 2)
print(f.tag.title)

这行得通,但感觉真的很 hackish :( 有没有更好的方法在 Kaitai Struct 和 Python 中做到这一点?

【问题讨论】:

【参考方案1】:

Kaitai Struct 即将推出的 v0.4 中有一个新功能可以准确解决这个问题。您可以使用_io 获取当前流对象,然后您可以使用.size 获取当前流的全长(以字节为单位)。因此,如果您想通过与流末尾的固定偏移量来处理某些结构,您需要在 .ksy 中使用类似的东西:

instances:
  tag:
    pos: _io.size - 128
    type: id3v1_tag

请注意,虽然当前稳定版是 v0.3,但您必须从 Github 下载并构建编译器 + 运行时并使用最新版本。

【讨论】:

谢谢!这可能解决它就好了!我试过REPL - 它报告v0.4,但它似乎不支持_io.size。是我自己还是那里有什么错误? 是的,它还没有更新。请继续关注 v0.4 版本,希望它会在本周发布。 v0.4 已发布!随意检查!

以上是关于Python:使用 Kaitai Struct 读取 ID3v1 标签的主要内容,如果未能解决你的问题,请参考以下文章

在stm32上使用kaitai struct

更好地理解 Kaitai Struct 的 32 位转换器

kaitai struct 中实现了哪些解析器技术?它是不是实现回溯?

问题:如何在kaitai中写`010 switch and if`

使用 Struct 列类型读/写 Parquet

pandas读数据出现struct.error