前面分析了MS Excel电子表格xlsx和xlsb的格式和读写,rusty_sheet还能读取ODS电子表格,它属于办公应用程序开放文档格式(Open Document Format for Office Applications)(ODF)。ODF 包括几种文件类型,用于开放文档文本文档的 ODT(OpenDocument Text)和电子表格ODS(OpenDocument Spreadsheet)。
要读取ODS文件,那首先要生成它,在pypi.org上找到了几个可生成ODS的包,其中最简单的是odswriter包,它没有任何依赖包,便于研究。附带的例子经过我修改如下,修改的方面及原因后续提及:
import datetime
import decimal
import odswriter as ods
# Single sheet mode
with ods.writer(open("test.ods","wb")) as odsfile:
sheet1=odsfile.new_sheet("Sheet1")
sheet1.writerow(["String", "ABCDEF123456", "123456","string3","string4"])
# Lose the 2L below if you want to run this example code on Python 3, Python 3 has no long type.
sheet1.writerow(["Float", 1, 123, 123.123, decimal.Decimal("10.321")])
sheet1.writerow(["Date/DateTime", datetime.datetime.now(), datetime.date(1989, 11, 9)])
sheet1.writerow(["Time",datetime.time(13, 37),datetime.time(16, 17, 18)])
sheet1.writerow(["Bool", True, False, True])
sheet1.writerow(["Formula", 1, 2, 3, ods.Formula("IF(A1=2,B1,C1)")])
# Multiple sheet mode
with ods.writer(open("test-multi.ods","wb")) as odsfile:
bears = odsfile.new_sheet("Bears")
bears.writerow(["American Black Bear", "Asiatic Black Bear", "Brown Bear", "Giant Panda", "Qinling Panda",
"Sloth Bear", "Sun Bear", "Polar Bear", "Spectacled Bear"])
sloths = odsfile.new_sheet("Sloths")
sloths.writerow(["Pygmy Three-Toed Sloth", "Maned Sloth", "Pale-Throated Sloth", "Brown-Throated Sloth",
"Linneaeus's Two-Twoed Sloth", "Hoffman's Two-Toed Sloth"])
安装odswriter运行例子程序
pip install odswriter
或
python3 pip.pyz install odswriter --break-system-package
python3 odswrt.py
没有任何提示,当前目录下生成了test.ods和test-multi.ods。
ODS 文件中有很多值得探索的内容,它的本质是一个 Zip 文件,用压缩工具可以打开和解压缩,包括content.xml、mimetype、styles.xml和一个META_INF目录及位于该目录下的manifest.xml,其中content.xml包含所有的数据。
先使用rusty_sheet插件去读取,
D load rusty_sheet;
D .system python3 odswrt.py
D from read_sheet('test.ods');
┌───────────────┬────────────────────────────┬─────────────┬─────────┬─────────┐
│ String │ ABCDEF123456 │ 123456 │ string3 │ string4 │
│ varchar │ varchar │ varchar │ varchar │ double │
├───────────────┼────────────────────────────┼─────────────┼─────────┼─────────┤
│ Float │ 1 │ 123 │ 123.123 │ 10.321 │
│ Date/DateTime │ 2025-08-18T08:12:45.987158 │ 1989-11-09 │ NULL │ NULL │
│ Time │ PT13H37M00S │ PT16H17M18S │ NULL │ NULL │
│ Bool │ true │ false │ true │ NULL │
│ Formula │ 1 │ 2 │ 3 │ NULL │
└───────────────┴────────────────────────────┴─────────────┴─────────┴─────────┘
D from read_sheet('test-multi.ods');
┌─────────────────────┬────────────────────┬────────────┬─────────────┬───────────────┬────────────┬──────────┬────────────┬─────────────────┐
│ American Black Bear │ Asiatic Black Bear │ Brown Bear │ Giant Panda │ Qinling Panda │ Sloth Bear │ Sun Bear │ Polar Bear │ Spectacled Bear │
│ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────────────────┴────────────────────┴────────────┴─────────────┴───────────────┴────────────┴──────────┴────────────┴─────────────────┤
│ 0 rows │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
D from read_sheet('test-multi.ods',sheet_name='Sloths');
┌────────────────────────┬─────────────┬─────────────────────┬──────────────────────┬─────────────────────────────┬──────────────────────────┐
│ Pygmy Three-Toed Sloth │ Maned Sloth │ Pale-Throated Sloth │ Brown-Throated Sloth │ Linneaeus's Two-Twoed Sloth │ Hoffman's Two-Toed Sloth │
│ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │
├────────────────────────┴─────────────┴─────────────────────┴──────────────────────┴─────────────────────────────┴──────────────────────────┤
│ 0 rows │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
D
再来说说原始示例代码的问题。
问题1:缺少odsfile.new_sheet(“Sheet1”)语句,生成的content.xml的table标签是<table:table table:style-name="ta1">,缺少table:name属性。
用rusty_sheet读取报错如下
D from read_sheet('test.ods');
Binder Error:
Read spreadsheet failed: Sheet not found or spreadsheet is empty
如果只添加odsfile.new_sheet(“Sheet1”),不修改其他内容同样不能成功读取,这时生成的content.xml的table标签是
<table:table table:name="Sheet1" table:style-name="ta1"/>
<table:table table:style-name="ta1">
它建立了一个名为Sheet1的工作表,但在此工作表下没有数据,真正的数据在它后面那个无名工作表中。这会导致rusty_sheet报错
D from read_sheet('test.ods');
Binder Error:
Read spreadsheet failed: Empty sheet or missing data
只有像上述代码那么修改,将新建的sheet赋给一个对象,再在此对象中执行writerow
sheet1=odsfile.new_sheet("Sheet1")
sheet1.writerow
才能将数据和工作表绑定,生成的结果如下
<table:table table:name="Sheet1" table:style-name="ta1"><table:table-row><table:table-cell office:value-type="string">
这样一来,单sheet和多sheet的ODS写法其实是一样的。
问题2:各行列数不一致
原始代码第2行列数最多,这会导致rusty_sheet报错
D from read_sheet('test.ods');
Read spreadsheet failed: Missing column name at 'D1'
因为rusty_sheet默认数据含标题行,不允许标题行有的列为空,这个既可以用加两列数据来解决,也可以指定header=0选项,让它自动生成标题行,即数据库表的列名。
加两列数据的结果如上表所示,header=0的效果如下表所示
D .system python3 odswrt.py
D from read_sheet('test.ods',header=0);
┌───────────────┬────────────────────────────┬─────────────┬─────────┬─────────┐
│ column1 │ column2 │ column3 │ column4 │ column5 │
│ varchar │ varchar │ varchar │ varchar │ double │
├───────────────┼────────────────────────────┼─────────────┼─────────┼─────────┤
│ String │ ABCDEF123456 │ 123456 │ NULL │ NULL │
│ Float │ 1 │ 123 │ 123.123 │ 10.321 │
│ Date/DateTime │ 2025-08-18T09:04:13.455374 │ 1989-11-09 │ NULL │ NULL │
│ Time │ PT13H37M00S │ PT16H17M18S │ NULL │ NULL │
│ Bool │ true │ false │ true │ NULL │
│ Formula │ 1 │ 2 │ 3 │ NULL │
└───────────────┴────────────────────────────┴─────────────┴─────────┴─────────┘
另外提一句,这个示例电子表格其实不适合用数据库表来表示,因为它每行的相同列数据类型不同,反而是同一行的数据类型相同,需要转置才符合通常的表格要求。

739

被折叠的 条评论
为什么被折叠?



