Python:解析二进制STL文件

3
我正在使用Python(2.7.1 32位和Windows 7 64位)解析二进制STL文件时遇到一些困难。该文件大约有450k大小,但是在解析了约8600个三角形中的244个后,我的解析器突然停止工作,并出现struct.unpack异常:
Exception unpack requires a string argument of length 12
在文件中的光标位置为第33行,第929行。但该行包含约3400个字符,因此这似乎不是换行符问题。
以下是代码:
import struct

normals = []
points = []
triangles = []
bytecount = []

fb = [] # debug list

def unpack (f, sig, l):
    s = f.read (l)
    fb.append(s)
    return struct.unpack(sig, s)

def read_triangle(f):
    n = unpack(f,"<3f", 12)
    p1 = unpack(f,"<3f", 12)
    p2 = unpack(f,"<3f", 12)
    p3 = unpack(f,"<3f", 12)
    b = unpack(f,"<h", 2)

    normals.append(n)
    l = len(points)
    points.append(p1)
    points.append(p2)
    points.append(p3)
    triangles.append((l, l+1, l+2))
    bytecount.append(b[0])


def read_length(f):
    length = struct.unpack("@i", f.read(4))
    return length[0]

def read_header(f):
    f.seek(f.tell()+80)

def write_as_ascii(outfilename):
    f = open(outfilename, "w")
    f.write ("solid "+outfilename+"\n")
    for n  in range(len(triangles)):
        f.write ("facet normal {} {} {}\n".format(normals[n][0],normals[n][1],normals[n][2]))
        f.write ("outer loop\n")
        f.write ("vertex {} {} {}\n".format(points[triangles[n][0]][0],points[triangles[n][0]][1],points[triangles[n][0]][2]))
        f.write ("vertex {} {} {}\n".format(points[triangles[n][1]][0],points[triangles[n][1]][1],points[triangles[n][1]][2]))
        f.write ("vertex {} {} {}\n".format(points[triangles[n][2]][0],points[triangles[n][2]][1],points[triangles[n][2]][2]))
        f.write ("endloop\n")
        f.write ("endfacet\n")
    f.write ("endsolid "+outfilename+"\n")
    f.close()

def main():
    infilename = r"cupHemis46_28.stl"
    outfilename = r"cupHemis46_28_ascii_test.stl"

    try:
        f = open ( infilename, "r")

        read_header(f)
        l = read_length(f)
        try:
            while True:
                read_triangle(f)
        except Exception, e:
            print "Exception",e[0]
        print len(normals), len(points), len(triangles), l
        write_as_ascii(outfilename)

    except Exception, e:
        print e


if __name__ == '__main__':
    main()

unpack函数(不是来自struct)收集所有将写入文件的字符串。当我比较两个文件时,它们似乎相等,直到unpack停止工作的文件位置。我用Notepad++打开了二进制文件,下一个字符是“SUB”。

我是否没有意识到任何与文件大小或字符限制有关的unpack限制?我的代码有什么问题吗?提前致谢。


我推荐这个难以找到的维基百科页面http://en.wikipedia.org/wiki/STL_%28file_format%29。虽然它不是一个好的文件格式,但几乎每个3D查看器软件或可视化工具包都知道并处理它,这导致了广泛的分布。 - DaClown
你能解释一下你为什么调用了两次f.read()吗?是在read_length函数中吗?还是你已经修改了代码?我尝试运行了一下,但是出现了相同的错误。 - BigBoy1337
我认为我已经编辑了代码,请查看我的问题日志以了解更改。我的问题的答案是Marcelo Cantos回复的第二部分,我的原始代码在ASCII模式下打开文件并很早就找到了EOF。如果您在二进制模式下打开它(请参见下面的答案),它将正常工作。 - DaClown
1个回答

10

你的解包函数调用了两次f.read。我怀疑你已经读取到了文件的末尾。

在Windows上以文本模式读取文件也会有问题。任何偶然出现的\r\n都将被读入为\n。进行如下更改可避免这个问题。

f = open(infilename, "rb")

你说得对,但这是我复制粘贴时的错误。我会编辑代码。即使我读取数据两次,我也应该能够解析出8000个三角形中的4000个,而不是250个。 - DaClown
第二部分有效了,我没有以二进制模式打开文件。非常感谢。 - DaClown
3
好的,听到这个消息很高兴!我当时有些困惑,后来想起在Windows中,流中的^Z(ASCII 27)会被解释为EOF。你可能早早地按了一次它。 - Marcelo Cantos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接