【问题标题】:Searching Binary Data in Ruby在 Ruby 中搜索二进制数据
【发布时间】:2010-08-06 16:47:44
【问题描述】:

仅使用纯 ruby​​(或有理由常见的 gem)是否有一种有效的方法来搜索 large 二进制文档以查找特定的字节字符串?


更深层次的背景:mpeg4 容器格式是一个 4 字节索引的序列化数据结构,无需完全解析该结构(我可以假设它是有效的)我想拉出特定的标签。

对于那些在它工作之前没有遇到过这个“dmap”序列化的人:

<4-byte length<4-byte tag><4-byte length><4-byte type definition><8 bytes of something I can't remember><data>

例如,这将“tvsh”(或 TV Show)标签定义为“Futurama”

00 00 00 20  ... 
74 76 73 68  tvsh
00 00 00 18  ....
64 61 74 61  data
00 00 00 01  ....
00 00 00 00  ....
46 75 74 75  Futu
72 61 6D 61  rama

确切的结构并不重要,我想写一个方法,当我给它'tvsh'时,它可以提取节目名称,如果我给它'tvsn',它是第2季。

我的第一个计划是使用正则表达式,但我有(不合理的)感觉这会很慢。

让我知道你的想法!提前致谢

【问题讨论】:

  • 在 Ruby 中打开文件时,您可以为二进制文件添加标志 b,例如 File.open("test.mpg", "rb")。这会有帮助吗?
  • 您的“大型二进制文档”是否太大而无法放入 RAM?
  • 二进制仅在 Windows 上需要。仅供参考
  • 这是一个 MPEG4 视频,所以它可能是 8GB,太大而无法放入内存!

标签: ruby regex binary-data


【解决方案1】:

在 Ruby 中,您可以在创建正则表达式时使用 /n 标志来告诉 Ruby 您的输入是 8 位数据。

您可以使用 /(.{4})tvsh(.{4})data(.{8})([\x20-\x7F]+)/n 匹配 4 个字节、tvsh、4 个字节、data、8 个字节和任意数量的 ASCII 字符。我看不出为什么这个正则表达式的执行速度比手动编写类似的搜索要慢得多。如果您不关心 4 字节和 8 字节块,/tvsh.{4}data.{8}([\x20-\x7F])/n 应该几乎与 tvsh 的文字文本搜索一样快。

【讨论】:

  • 如果我在我的二进制数据中尝试这个,我会得到“UTF-8 中的无效字节序列(ArgumentError)”
  • 如果字符串为 ASCII-8BIT 则有效。默认为UTF-8。您可以使用String#force_encoding 更改它,例如:bindata.force_encoding("ASCII-8BIT")
【解决方案2】:

如果我正确理解您的描述,整个文件由许多这样的固定结构“块”组成?

在这种情况下,我建议您逐一扫描,并跳过您不感兴趣的。所以,你的每一步都应该做到以下几点:

  1. 读取 8 个字节(使用IO#readbytes 或类似方法)
  2. 从读取头中提取size(前4个字节)和tag(后4个字节)
    1. 如果标签是您需要的标签,请跳过后面的 16 个字节并读取 size-24 字节。
    2. 如果标签不感兴趣,请跳过size-16 字节。
  3. 重复。

对于跳过字节,您可以使用IO#seek

【讨论】:

  • 该格式的一个令人讨厌的方面是原子(块)可以嵌套。
  • 有这个库,不过没用过:github.com/arbarlow/ruby-mp4info
  • 这必须是正确的前进方向,这样我就不必扫描我实际上不需要的所有原子(似乎大多数 mov 文件在 end 都有元数据 文件)。只需要弄清楚要推入哪些原子!哦,弄清楚为什么有些不符合这种模式……
【解决方案3】:

理论上,您可以对任意数据使用正则表达式,包括二进制字符串。 HTH。

【讨论】:

  • 没有任何理论依据,只要您使用的正则表达式引擎具有一个字节等于一个字符的 8 位模式。
猜你喜欢
  • 1970-01-01
  • 2023-03-17
  • 2011-03-14
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 2017-08-12
  • 2023-04-03
  • 2019-10-23
相关资源
最近更新 更多