【问题标题】:to parse a file with text (with offset information) and binary data in python在 python 中解析带有文本(带有偏移信息)和二进制数据的文件
【发布时间】:2011-05-13 17:34:28
【问题描述】:

我有一个xml文件,其中包含一组文本元素标签(每个标签包含相应二进制元素的十进制偏移值和数据长度)以及末尾所有元素的整个二进制数据。一个例子如下。

<?xml version="1.0" encoding="UTF-8"?>
<Package>
  <element>
        <offset>0</offset>
        <length>2961181</length>
        <checksum>4238515972</checksum>
        <format>gzip</format>
  </element>
  <element>
        <offset>2961181</offset>
        <length>5442</length>
        <checksum>4238515972</checksum>
        <format>bin</format>
  </element>
</Package>
BINARY_DATA

请注意,偏移量是十进制的,从标头之后的第一个字节开始计算。 如何在python中解析这个文件,根据偏移量抓取对应的元素,解压缩(如果它的格式是gzip)并将其存储为文件?

嗯,根据 OmnipotentEntity 和 Jakob_B 的回复,我制作了以下简短的脚本,看看它是否适用于第一个元素:

import zlib

f = open("file.xml", "r")
text = f.read()
position = text.find("</Package>\n")
headerSize=position+ len("</Package>\n") + 1 
offset=0
f.seek(headerSize + offset) 
length = 2961181
bin_data = f.read(length)
zipped=1
if (zipped):
  ungziped_str = zlib.decompressobj().decompress('x\x9c' + bin_data)
  print(ungziped_str)
f.close()

但是,我收到以下错误:

Traceback(最近一次调用最后一次): 文件“file_parse.py”,第 11 行,在? ungziped_str = zlib.decompressobj().decompress('x\x9c' + bin_data) zlib.error: 解压时出错 -3: 无效的块类型

有什么问题?输入文件不正确,还是代码不正确?

【问题讨论】:

  • 如果我在您的测试 XML(在 XML 之后具有 BINARY_DATA 的那个)上运行它并设置 length=10 进行测试,我会得到“INARY_DATA”。请记住,编程中只有三种类型的错误:意外输入和非一错误。
  • 谢谢你,Spacedman,一个错误,我改为 headerSize=position+ len("\n"),但还有另一个错误:ungziped_str = zlib.decompressobj() .decompress('x\x9c' + bin_data) zlib.error: Error -3 while decompressing: invalid stored block lengths
  • 如果我们没有文件可玩,可能很难调试。最好不要太大。

标签: python parsing file binary-data


【解决方案1】:

诀窍是阻止 XML 解析器处理二进制数据。 lxml 允许您一次将一行输入到解析器,因此您可以观察最后一个 XML 标记并停在那里:

from lxml import etree

def process(filename):
    f = file(filename,"r")
    parser = etree.XMLParser()
    for l in f:
        parser.feed(l)
        if l=="</Package>\n":
            break
    return parser.close()

返回一个

r=process("junk.xml")
<Element Package at 9f14eb4>

这是一个 lxml 对象,您可以从中获取数据。第二个对象的偏移量在这里:

>>> r[1][0].text
'2961181'

等等。这应该足以让您制定可行的解决方案。但请注意以 Package 标签结尾的行,可能有更好的方法来做到这一点,如果文件有不同的行结尾,这可能不起作用。

【讨论】:

  • 是的!这是正确的做法哟!我不知道逐行提供解析器。 @pepero:这是一种专有的存储方法吗?
【解决方案2】:

为什么不使用 lxml 搜索结束标记?然后,当找到结束标记时,只需 .seek() 到该点并读取二进制数据。

【讨论】:

    【解决方案3】:

    确定标题大小。

    使用 xml 魔法获取偏移量和数据长度

    import zlib
    python.seek(headerSize+offset)
    mydata = python.read(length)
    if (zipped):
      ungziped_str = zlib.decompressobj().decompress('x\x9c' + mydata)
    

    然后正常写入文件。

    gunzip 魔法来源http://codingrecipes.com/ungzip-a-string-in-python-gzinflate-in-python

    【讨论】:

    • 据我了解,在解析 xml 标头之前,您不了解偏移量。此外,在上面的示例中,xml 中指定了两个二进制部分。真正的问题是如何读取和解析 xml - 因为我们不知道 xml 的结束位置。
    • 嗨,OmnipotentEntity,感谢您的回答。正如 vonPetrushev 指出的那样,不了解偏移值等,因此可能应该首先将 xml 读取为字符串,并构建所有元素的 (offset, length) 对的数据结构,然后找到/解压缩/写。如果这是正确的,(偏移量,长度)对部分将是什么样的?
    猜你喜欢
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 2014-11-29
    相关资源
    最近更新 更多