【问题标题】:Extract string from a binary file on Windows and Linux using python/grep使用 python/grep 从 Windows 和 Linux 上的二进制文件中提取字符串
【发布时间】:2021-02-23 20:21:55
【问题描述】:

我需要我的代码同时在 Linux 和 Windows 上工作。我有一个二进制文件,其中包含一个带有DateTime 信息的文本标题,我想提取这些信息。提取部分的示例(即信息如何保存在 txt 标头中)在代码的注释部分中。整个代码都是用 Python 编写的,所以我希望这个提取也用 Python 完成。在 Linux 中,我会简单地使用 subprocessgrep (ref):

import subprocess
hosts = subprocess.check_output("grep -E -a 'Date' /path/Bckgrnd.bip", shell=True)
sentence = hosts.decode('utf-8')
# '----------------------------  Date:09/09/2020   Time:11:26:19  ----------------------------\n  Capture Time/Date:\t11:26:17 on 09/09/2020\n----------------------------  Date:09/09/2020   Time:11:26:19  ----------------------------\n'

date = sentence[sentence.index('Date:')+5:sentence.index('Date:')+13]
time = sentence[sentence.index('Time:')+5:sentence.index('Time:')+13]
print(date, time)
# 09/09/20 11:26:19

问题是这在 Windows 上会失败。另一种方法是在 Python 中加载文件:

file_input = /path/Bckgrnd.bip
with open(file_input, 'rb') as f:
    s = f.read()
print(s.find(b'Date'))
# 498
date = s[s.find(b'Date')+5:s.find(b'Date')+13].decode('utf-8')
time = s[s.find(b'Time')+5:s.find(b'Time')+13].decode('utf-8')
print(date, time)

这有一个主要问题。它必须将整个文件读入内存,如果文件很大,那就是个问题。有没有办法用 grep 解决操作系统问题?在不加载整个二进制文件的情况下,在纯 python 中是否有替代方案?

更新: 关于速度——我相信grep 比纯 Python 更快,因此拥有它不仅会在内存方面而且在速度方面会更好。

请注意,即使 grep 也将其视为二进制文件(如提到的 -a 标签,例如 here)。

【问题讨论】:

    标签: python linux windows grep


    【解决方案1】:

    无论如何,您都必须搜索整个文件,即使 grep 也会这样做。但是,您不必将整个文件加载到内存中,一次只搜索一行即可。

    file_input = '/path/Bckgrnd.bip'
    with open(file_input, 'rb') as f:
        for line in f.readlines():
            if b'Date' in line:
                s = line
                date = s[s.find(b'Date')+5:s.find(b'Date')+13].decode('utf-8')
                time = s[s.find(b'Date')+5:s.find(b'Date')+13].decode('utf-8')
                print(date, time)
                break  # Only break here if you expect exactly one match
    

    您也许还可以使用 strftime 改进日期和时间提取,但我不确定您使用的确切格式,所以我没有花任何时间尝试这样做。

    您说该文件是二进制文件,但您将其解码为 UTF-8,这让我认为它是文本。也使用 grep 让我思考文本。

    如果它真的是二进制的并且没有很多换行符,那么你可以一次读取一个字节的文件。

    file_input = '/path/Bckgrnd.bip'
    buffer = bytes()
    with open(file_input, 'rb') as f:
        buffer = buffer[1:] + f.read(1)
        if buffer == b'Date':
            # Read the next set of however many bytes you need to interpret the date and time
    

    最后一点,这不会让您的程序更快,但会减少您的内存使用量。

    【讨论】:

    • 好点,我会澄清问题,谢谢。是的,我的意思是记忆,而不是速度:)。虽然我相信 grep 在这方面比纯 python 更快..
    • Grep 对于长文件会更快,但对于短文件,可能不是因为启动进程需要多长时间。如果您正在处理足够大的文件,则可以找到适用于 Windows 的 grep 克隆。如果你真的需要,你可以在你的发行版中包含那个二进制文件。我的建议是做一些基准测试。您可能会发现纯 python 解决方案已经足够好了。如果没有,那么您至少可以确信您的额外工作是合理的。
    • 我已经将它们写入一个函数并运行一个快速的%timeit 测试,这让我很惊讶。我原来的纯 python 解决方案比你的更快:2.43 ms ± 67.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)17 ms ± 121 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)。我已经删除了 print 函数,因为它非常慢。有内幕吗?
    • 哪种解决方案?行还是字节?你的输入文件有多大?如果没有看到您正在解析的数据,我很难有很大的把握。
    • 在无法运行的情况下,我很难独立调查,但我可以猜到。我的线路解决方案对每一行执行搜索 (in),然后复制您的 find 调用。一次加载文件可以防止额外的搜索,而且您可能会为此付出启动成本。最好搜索 1M 一次而不是 1K 1000 次。对于只有几 MB 的文件,我不会强调将其全部加载到内存中,这对于现代系统来说并不是很多。减少内存通常会以速度为代价,但您似乎不需要为此付出代价。
    猜你喜欢
    • 1970-01-01
    • 2012-09-05
    • 2012-10-29
    • 2018-04-08
    • 1970-01-01
    • 2011-09-09
    • 2018-12-15
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多