不带元数据的简单Python xlsx文件比较

时间:2018-10-01 16:41:29

标签: python pandas

有没有一种简单的方法可以比较python中忽略元数据的两个xlsx文件?尝试测试脚本的输出是否与预期的xlsx文件匹配。

我正在寻找诸如filecmp.cmp()之类的东西,该文件不起作用,因为文件的元数据不同(我认为唯一的区别是它们是在不同的时间写的)。我看到其他人在谈论用熊猫读取文件,这不是我想要的,因为我不希望开销(我关心的不仅仅是数据)。

或者,如果我能确切地找出两者之间的元数据有什么不同,我可以引入一个变量以使脚本在作为测试套件的一部分运行时写一个假的测试日期(与预期文件中的日期匹配)。

编辑:通过在我的writer = pd.ExcelWriter(...)调用中指定engine ='xlsxwriter',我可以在writer.book上使用xlsxwriter的set_properties方法:

writer.book.set_properties({'created':datetime.date(1936,10,31)})。这使我每次都可以使用相同的创建日期来写入文件,并且简单的filecmp.cmp()通过。我仍然很想听听是否有办法避免这种情况,因为它很hacky,但是,嘿...它确实有效...

2 个答案:

答案 0 :(得分:0)

如果您有两个这样的文件

value1   value2   value3
0.456   3.456    0.4325436
6.24654 0.235435 6.376546
4.26545 4.264543 7.2564523

value1   value2  value3
0.456   3.456    0.4325436
6.24654 0.23546  6.376546
4.26545 4.264543 7.2564523

您可以尝试这样的事情...

from itertools import izip_longest
import xlrd

rb1 = xlrd.open_workbook('file1.xlsx')
rb2 = xlrd.open_workbook('file2.xlsx')

sheet1 = rb1.sheet_by_index(0)
sheet2 = rb2.sheet_by_index(0)

for rownum in range(max(sheet1.nrows, sheet2.nrows)):
    if rownum < sheet1.nrows:
        row_rb1 = sheet1.row_values(rownum)
        row_rb2 = sheet2.row_values(rownum)

        for colnum, (c1, c2) in enumerate(izip_longest(row_rb1, row_rb2)):
            if c1 != c2:
                print "Row {} Col {} - {} != {}".format(rownum+1, colnum+1, c1, c2)
    else:
        print "Row {} missing".format(rownum+1)

这将显示两个文件之间不同的所有单元格。对于给定的两个文件,将显示:

  

第3行2-0.235435!= 0.23546

答案 1 :(得分:0)

Xlsx文件是Zip容器中XML文件的集合。要使两个xlsx文件与二进制等效,则:

  1. XML文件必须完全相同。
  2. zip必须以相同的方式完成。

对于XlsxWriter文件,可能对于大多数软件,其zip相同。但是,软件之间可能并不相同。

XML部分不太可能是相同的。

第一个元数据差异可能是压缩之前文件上的系统时间戳(因为数据存储在zip中)。对于XlsxWriter> = 1.0.4的版本,此时间戳始终像Excel一样始终为'1980-01-01 00:00:00',因此它将相同。

Excel还会在文件中添加有关作者和创建/修改时间的元数据,因此任何两个文件之间相隔一秒的时间都会有所不同。

此元数据存储在XML集合内的“ docProps / core.xml”文件中:

$ xmllint --format example/docProps/core.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="...">
  <dc:creator>John</dc:creator>
  <cp:lastModifiedBy>John</cp:lastModifiedBy>
  <dcterms:created xsi:type="dcterms:W3CDTF">2018-02-23T21:20:58Z</dcterms:created>
  <dcterms:modified xsi:type="dcterms:W3CDTF">2018-02-25T02:13:23Z</dcterms:modified>
</cp:coreProperties>

为了使它们在XlsxWriter中保持一致,您可以设置created document property

workbook.set_properties({'created':  datetime.date(2018, 1, 1))

这是您所指的“ hacky”方法,但实际上是有效的。它允许进行二进制cmp风格的比较。

XlsxWriter试图与Excel具有很高的兼容性,因此它进行了约700个测试,将其输出与Excel创建的文件进行了比较。为此,它使用了一个名为compare_xlsx_files()的测试函数。在进行比较时,这会忽略日期样式元数据,还会忽略其他元数据“ rel”文件中某些元素的顺序,这些顺序可能会有所不同。它还使您可以在进行比较时忽略某些文件或带有文件的元素。它不是由模块导出的,但是如果需要的话可以使用。