调用uno创建实例触发段错误,如何用uno打开Calc表格?
问题
需要处理包含多个工作表的Calc表格,按照文档基金会Wiki的Python指南操作,已安装libreoffice-script-provider-python包,可正常导入uno库,但调用create_instance函数时Python解释器会因段错误崩溃。
示例代码:
import uno CTX = uno.getComponentContext() SM = CTX.getServiceManager() def create_instance(name, with_context=False): if with_context: instance = SM.createInstanceWithContext(name, CTX) else: instance = SM.createInstance(name) return instance path = uno.systemPathToFileUrl('/home/user/temp/test.ods') desktop = create_instance('com.sun.star.frame.Desktop', True) doc = desktop.loadComponentFromURL(path, '_default', 0, ())
环境配置:
- 操作系统:Ubuntu 22.04
- Python版本:3.10.12
- LibreOffice版本:7.3.7
更新:简化测试后的日志,提前启动Calc仍出现段错误:
$ soffice --calc --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" $ python3 Python 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import uno >>> CTX = uno.getComponentContext() >>> SM = CTX.getServiceManager() >>> name='com.sun.star.frame.Desktop' >>> instance = SM.createInstanceWithContext(name, CTX) Segmentation fault (core dumped)
解决方案
段错误源于直接使用本地uno.getComponentContext()获取的上下文,无法正确与LibreOffice服务管理器交互。正确做法是通过socket连接到已启动的LibreOffice实例,获取远程服务上下文。
步骤1:启动带监听的LibreOffice
在终端启动Calc并开启socket监听:
soffice --calc --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" --headless
加上
--headless可后台运行(无GUI);需要可视化界面则移除该参数。
步骤2:修改Python代码连接远程服务
替换原有代码,改为通过socket连接到LibreOffice实例:
import uno # 建立本地上下文并获取解析器 local_context = uno.getComponentContext() resolver = local_context.ServiceManager.createInstanceWithContext( "com.sun.star.bridge.UnoUrlResolver", local_context ) # 连接到LibreOffice实例的服务上下文 CTX = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" ) SM = CTX.getServiceManager() def create_instance(name, with_context=False): if with_context: instance = SM.createInstanceWithContext(name, CTX) else: instance = SM.createInstance(name) return instance # 转换本地路径为LibreOffice可识别的URL path = uno.systemPathToFileUrl('/home/user/temp/test.ods') # 获取Desktop服务并加载文档 desktop = create_instance('com.sun.star.frame.Desktop', True) doc = desktop.loadComponentFromURL(path, '_default', 0, ()) # 示例:获取第一个工作表并打印名称 sheets = doc.getSheets() first_sheet = sheets.getByIndex(0) print(f"第一个工作表名称:{first_sheet.getName()}") # 操作完成后关闭文档(可选) doc.close(True)
额外排查点
- 端口占用检查:若2002端口被占用,更换为其他端口(如2003),同时修改代码中的端口号。
- 重新安装Python绑定:Ubuntu下的
libreoffice-script-provider-python可能存在版本匹配问题,执行以下命令重装:sudo apt remove --purge libreoffice-script-provider-python sudo apt install libreoffice-script-provider-python - Python版本兼容:LibreOffice 7.3.x默认适配Python 3.8,若问题仍存在,尝试用Python 3.8运行代码。
内容的提问来源于stack exchange,提问作者Luís de Sousa
相关产品推荐
相关产品推荐

