银河麒麟系统 XLS 批量无损转 XLSX 完整解决方案
本文介绍了在银河麒麟V10国产化操作系统下实现xls格式报表自动化转换的解决方案。针对内网环境下无法联网、格式要求严格等痛点,对比分析了WPS、Python库和LibreOffice三种方案,最终推荐使用LibreOffice作为最优解。文章详细提供了LibreOffice 25.8.7.2版本的离线安装教程,包括x86和ARM架构的下载链接、解压安装步骤、软链接创建方法等关键操作,并给出了完整的
📌 博客标签:#银河麒麟 #国产化 #Python #Excel处理 #LibreOffice #内网离线部署
📌 阅读难度:新手友好、运维开发通用
📌 适用人群:国产化办公、内网运维、Python自动化、政务涉密内网
一、前言(业务真实场景)
1.1 业务背景
目前大量政务、国企、事业单位使用银河麒麟V10国产化操作系统,存在大量老旧 .xls 格式报表。日常工作中存在以下痛点:
-
内网环境无外网、禁止联网,不能随意安装软件;
-
xls为老旧二进制格式,人工转换效率极低;
-
表格存在合并单元格、隐藏列、特殊格式、公式,普通转换工具格式丢失;
-
需要批量汇总:每一个Excel文件保留为独立Sheet,合并至同一个汇总文件。
1.2 硬性业务要求
-
禁止人工手动打开表格另存为,必须脚本自动化;
-
保留全部表格格式:边框、字体、行高、列宽、隐藏列、合并单元格;
-
批量读取xls第一个工作表,一个源文件对应一个Sheet;
-
适配x86_64、ARM64(飞腾/鲲鹏) 双架构。
二、技术选型对比(生产踩坑总结)
为实现xls无损转xlsx,本人实测三种方案,这里直接给出生产结论,避免大家重复踩坑。
2.1 WPS Linux(直接淘汰)
-
✅ 优点:图形界面打开表格格式完美;
-
❌ 致命缺陷:Linux版WPS无官方命令行转换接口;
-
❌ 网传
et --headless命令实测全部失效、表格损坏、格式丢失; -
结论:WPS不能做后台自动化转换。
2.2 纯Python库方案(xlrd+openpyxl)(不推荐)
-
❌ 无法解析老旧xls格式、表格宏、合并单元格、边框;
-
❌ xls二进制格式老旧,读取不稳定。
2.3 LibreOffice(最终生产方案,强烈推荐)
-
✅ 官方原生无头模式,后台静默转换;
-
✅ 转换逻辑等同于人工另存为,格式100%无损;
-
✅ x86、ARM架构命令完全一致;
-
✅ 支持内网离线安装,无网络依赖;
-
✅ 免费开源、国产化系统兼容性最好。
三、环境详细说明
3.1 系统环境
| 系统 | 架构 |
|---|---|
| 银河麒麟 V10 | x86_64 |
| 银河麒麟 V10 | ARM64(aarch64) |
3.2 软件版本(版本统一,生产规范)
为避免跨版本命令差异、运维混乱,本次全部统一版本:
-
x86_64:LibreOffice 25.8.7.2
-
ARM64:LibreOffice 25.8.7.2
3.3 软件依赖
-
Python3(系统自带)
-
openpyxl(Excel格式复制)
-
全程离线、无外网依赖
扩展知识点:为什么统一版本?
25.8系列为长期维护稳定版,x86/ARM编译同源,命令、参数、内核逻辑完全一致,后期运维、迁移、维护成本最低。
四、LibreOffice 离线安装教程(内网专用)
4.1 资源下载地址
官方历史包下载地址:https://downloadarchive.documentfoundation.org/libreoffice/old/
选择规则:
选版本:25.8.7.2
下载两个压缩包:
LibreOffice_25.8.7.2_Linux_x86-64_deb.tar.gz 主程序
LibreOffice_25.8.7.2_Linux_x86-64_deb_langpack_zh-CN.tar.gz 中文语言包
4.2 下载报错解决办法
部分浏览器打开直链提示:当前不支持该文件类型,请尝试其他文件
✅ 解决方式:鼠标右键链接 → 另存为,不要直接左键打开。
4.3 解压命令
- 下载得到两个
.tar.gz压缩包,放到麒麟桌面 libreoffice_all_deb_x86 文件夹进行解压安装:
# 【命令注释】cd=切换目录,~/Desktop=桌面,进入存放安装包的文件夹
cd ~/Desktop/libreoffice_all_deb_x86
# 【验证命令】执行后查看文件夹内的文件(可选,确认文件存在)
ls
执行ls后能看到两个.tar.gz文件,说明路径正确。
- 解压 主程序 + 中文语言包:Linux 压缩包必须用命令解压,依次执行以下 2 条解压命令(直接复制粘贴):
# 1. 解压 LibreOffice 主程序压缩包
tar -zxvf LibreOffice_25.8.7.2_Linux_x86-64_deb.tar.gz
# 2. 解压 LibreOffice 中文语言包压缩包
tar -zxvf LibreOffice_25.8.7.2_Linux_x86-64_deb_langpack_zh-CN.tar.gz
解压成功效果
文件夹内会生成两个新文件夹:
LibreOffice_25.8.7.2_Linux_x86-64_deb(主程序文件夹)
LibreOffice_25.8.7.2_Linux_x86-64_deb_langpack_zh-CN(中文包文件夹)
- 合并安装包:两个文件夹内都有DEBS子文件夹,我们需要把所有 deb 安装包放到同一个文件夹,方便一键安装:
# 1. 复制主程序的所有 deb 文件,粘贴到当前文件夹
cp ./LibreOffice_25.8.7.2_Linux_x86-64_deb/DEBS/*.deb ./
# 2. 复制中文语言包的所有 deb 文件,粘贴到当前文件夹
cp ./LibreOffice_25.8.7.2_Linux_x86-64_deb_langpack_zh-CN/DEBS/*.deb ./
✅ 执行完成后,当前文件夹已包含主程序 + 中文语言包所有安装文件。
4.4 X86/ARM通用离线安装步骤
- 批量安装:复制命令直接执行,全程自动安装,红色警告不用管:
# 【命令注释】sudo=获取管理员权限,dpkg -i=安装deb包,*.deb=安装所有安装包
sudo dpkg -i *.deb
- 离线修复系统依赖(必做!):麒麟离线安装会缺失依赖文件,执行命令自动修复:
# 【命令注释】自动修复缺失的系统依赖,保证软件正常运行
sudo apt -f install -y
4.5 创建软链接
麒麟系统离线安装后,默认不识别 libreoffice 命令,需要创建软链接(相当于 Windows 快捷方式)。
- 查找软件真实路径
# 【命令注释】全局查找 LibreOffice 主程序,屏蔽无用报错
sudo find / -name "soffice" -o -name "libreoffice" 2>/dev/null
✅ 99% 麒麟系统输出固定路径(直接复制备用):
/opt/libreoffice7.3/program/soffice
- 创建软链接(直接复制执行)
# 【命令注释】创建软链接,让系统识别 libreoffice 命令
sudo ln -sf /opt/libreoffice7.3/program/soffice /usr/bin/soffice
sudo ln -sf /opt/libreoffice7.3/program/soffice /usr/bin/libreoffice
✅ 无任何输出 = 软链接创建成功!
4.6 验证安装
libreoffice --version
输出版本号 25.8.7.2 即为安装成功。
扩展知识点:外网在线安装(有网环境备用)
若服务器可以联网,无需手动下载包,一键安装:
sudo apt update && sudo apt install libreoffice libreoffice-l10n-zh-cn -y
五、核心转换命令全参数详解
5.1 完整标准命令
libreoffice --headless --convert-to xlsx 源文件.xls --outdir 输出目录
5.2 逐参数傻瓜式讲解(每个参数都有注释 + 作用)
| 命令片段 | 官方名称 | 小白通俗解释 | 核心作用 |
|---|---|---|---|
libreoffice |
主程序命令 | 软件启动入口 | 调用系统已安装的 LibreOffice 软件 |
--headless |
无头模式 | 无图形界面、静默运行 | 不打开软件窗口、后台自动转换,服务器/脚本专用 |
--convert-to |
转换格式 | 指定要转换成什么文件 | 固定写法,后面接目标格式(如 xlsx/pdf/doc) |
xlsx |
目标格式 | 要转成的文件类型 | 本次需求:把老版 xls 转为新版 xlsx |
源文件.xls |
输入文件 | 你要转换的原始表格 | 必须是真实存在的 .xls 文件路径 |
--outdir |
输出目录 | 转换后的文件存哪里 | 指定保存文件夹,不写则默认保存在当前目录 |
5.3 关键参数深度说明(扩展知识点)
1. --headless(最重要!)
- 全称:无头模式(无图形界面模式)
- 作用:
- 不弹出 LibreOffice 软件窗口
- 不占用桌面资源
- 无弹窗、无等待、纯后台运行
- 适用场景:自动化脚本、服务器、内网无图形界面环境、批量转换
- 不写的后果:会弹出软件窗口,脚本卡死,无法自动化
2. --convert-to xlsx
- 固定语法:
--convert-to 格式名 - 支持的常见格式(可扩展使用):
xlsx:Excel 新版格式(本次使用)xls:Excel 老版格式pdf:PDF 格式csv:文本格式
- 本次固定写
xlsx,专门用于老旧.xls升级格式
3. --outdir 输出目录
- 作用:自定义转换后文件的保存位置
- 不写此参数:转换后的文件会和源文件放在同一个文件夹
- 推荐写法:指定独立文件夹,方便管理文件
5.4 3 个最常用实战示例(直接复制改路径就能用)
示例1:最简单用法(输出到当前目录)
# 转换 报表.xls 为 报表.xlsx,保存在当前文件夹
libreoffice --headless --convert-to xlsx 报表.xls
示例2:指定输出目录(推荐生产使用)
# 源文件:报表.xls
# 输出到:./output 文件夹(自动创建)
libreoffice --headless --convert-to xlsx 报表.xls --outdir ./output
示例3:绝对路径(麒麟脚本专用,最稳定)
# 完整路径写法,不会出现找不到文件的错误
libreoffice --headless --convert-to xlsx "/home/user/桌面/报表.xls" --outdir "/home/user/桌面/转换结果"
5.5 命令执行成功标志
执行命令后,终端输出如下内容,代表转换成功:
convert /home/user/桌面/报表.xls -> /home/user/桌面/转换结果/报表.xlsx using filter : Calc Office Open XML
5.6 小白必看注意事项
- 命令中路径不能有空格(麒麟系统偶尔兼容问题)
- 源文件不能被 WPS/LibreOffice 打开(文件被占用会转换失败)
- 必须先安装 LibreOffice 并配置软链接,否则提示
command not found - 批量转换时,此命令会被 Python 脚本自动调用,无需手动执行
5.7 扩展知识:一键转 PDF(额外实用技能)
如果后续需要转 PDF,只改格式参数即可,命令完全通用:
# xls 转 PDF 格式
libreoffice --headless --convert-to pdf 源文件.xls --outdir 输出目录
扩展知识点:无头模式原理
headless模式不加载GUI图形渲染模块,占用资源极低、无弹窗、适合服务器、自动化脚本、后台定时任务。
六、Python脚本迭代开发全过程
6.1 第一版:单文件转换函数
直接调用系统命令,实现单个xls无损转换。
def xls_to_xlsx_libreoffice(xls_file: Path, out_dir: Path):
"""
麒麟系统专用:调用LibreOffice进行xls转xlsx
:param xls_file: 源xls文件路径
:param out_dir: 输出文件夹
"""
# 组装命令
cmd = [
"libreoffice",
"--headless",
"--convert-to", "xlsx",
str(xls_file),
"--outdir", str(out_dir)
]
# 执行系统命令(LibreOffice 格式转换),捕获输出信息,不打印到终端
subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
扩展知识
| 参数部分 | 专业含义 | 小白通俗解释 | 咱们脚本里的作用 |
|---|---|---|---|
subprocess |
Python 内置子进程模块 | Python 自带的「系统命令执行工具」 | 让 Python 能调用 Linux 命令 |
.run() |
执行方法 | 运行命令的开关 | 执行 LibreOffice 转换指令 |
cmd |
命令列表 | 咱们拼接好的 LibreOffice 转换命令 | 执行 xls → xlsx 格式转换 |
stdout=subprocess.PIPE |
捕获标准输出 | 把命令的正常提示信息藏起来,不显示在终端 | 不打印杂乱日志,脚本更干净 |
stderr=subprocess.PIPE |
捕获标准错误 | 把命令的报错信息藏起来,统一管理 | 转换失败时能拿到错误原因 |
encoding="utf-8" |
字符编码 | 支持中文文件名/路径,不乱码 | 解决中文报表名称乱码问题 |
优点:静默运行、中文兼容、无杂乱输出、企业生产级标准。
6.2 第二版:批量转换函数
遍历文件夹,自动过滤临时缓存文件,批量转换。
def batch_convert_xls(input_folder: str):
"""
批量转换文件夹内所有xls为xlsx
:param input_folder: 存放xls的文件夹
:return: 转换完成后的xlsx路径列表
"""
# 转为绝对路径,防止路径出错
input_path = Path(input_folder).resolve()
# 创建临时存放目录
temp_dir = input_path / "temp_xlsx"
temp_dir.mkdir(exist_ok=True)
# 筛选正规xls文件,排除系统临时缓存文件 ~$开头
xls_files = [f for f in input_path.glob("*.xls") if not f.name.startswith("~$")]
if not xls_files:
print("❌ 未找到 .xls 文件")
return []
xlsx_list = []
for file in xls_files:
# 执行转换
xls_to_xlsx_libreoffice(file, temp_dir)
# 替换后缀,拼接新文件路径
xlsx_file = temp_dir / file.with_suffix(".xlsx").name
# 判断是否转换成功
if xlsx_file.exists():
xlsx_list.append(xlsx_file)
print(f"✅ 转换完成:{file.name}")
return xlsx_list
6.3 第三版:多Sheet合并(业务最终版)
需求:一个源文件 = 目标Excel一个独立Sheet,不堆叠、不合并单元格。
6.3.1 重大BUG记录(重点踩坑)
✅ BUG:隐藏列复制不全(A/B/C三列隐藏,仅复制A列)
✅ 原因:openpyxl仅记录人工手动修改过的列,默认隐藏列无法识别
✅ 尝试方案:遍历最大列、底层私有属性,全部报错
✅ 最终生产最优方案:复制完成后置强制隐藏指定列
# 强制隐藏ABC三列(生产稳定方案)
target_sheet.column_dimensions['A'].hidden = True
target_sheet.column_dimensions['B'].hidden = True
target_sheet.column_dimensions['C'].hidden = True
扩展知识点:openpyxl底层BUG原因
Excel默认格式列不会写入xml记录,openpyxl仅加载被人工修改过的列维度,原生隐藏列无法被读取,官方至今未修复。
七、最终生产级完整代码(可直接上线)
特点:注释齐全、无报错、保留全部格式、兼容双架构、强制修复隐藏列BUG。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
国产化银河麒麟 XLS批量转XLSX+多Sheet合并工具
适配:x86_64 / ARM64 架构
LibreOffice版本:25.8.7.2
作者:apollo_miracle
功能:每个xls第一个工作表,单独生成一个sheet,格式无损保留
"""
import openpyxl
from copy import copy
import os
import subprocess
from pathlib import Path
def copy_sheet_to_workbook(source_file, target_workbook, new_sheet_name):
"""
高精度工作表复制函数(自研稳定版)
保留:字体、边框、填充、对齐、行高、列宽、合并单元格
修复:隐藏列复制不全BUG,后置强制隐藏
"""
# 加载源表格,data_only=False保留格式
source_wb = openpyxl.load_workbook(source_file, data_only=False)
source_sheet = source_wb.worksheets[0] # 固定取第一个工作表
# 在目标工作簿新建工作表
target_sheet = target_workbook.create_sheet(title=new_sheet_name)
# 复制列宽
for col_idx in source_sheet.column_dimensions:
target_sheet.column_dimensions[col_idx].width = source_sheet.column_dimensions[col_idx].width
# 复制行高
for row_idx in source_sheet.row_dimensions:
target_sheet.row_dimensions[row_idx].height = source_sheet.row_dimensions[row_idx].height
# 复制合并单元格
for merged_range in source_sheet.merged_cells.ranges:
target_sheet.merge_cells(str(merged_range))
# 逐单元格复制内容+全套格式
for row in source_sheet.iter_rows():
for cell in row:
new_cell = target_sheet.cell(row=cell.row, column=cell.column, value=cell.value)
if cell.has_style:
new_cell.font = copy(cell.font)
new_cell.border = copy(cell.border)
new_cell.fill = copy(cell.fill)
new_cell.number_format = cell.number_format
new_cell.protection = copy(cell.protection)
new_cell.alignment = copy(cell.alignment)
# ===================== 核心BUG修复:强制隐藏A/B/C列 =====================
target_sheet.column_dimensions['A'].hidden = True
target_sheet.column_dimensions['B'].hidden = True
target_sheet.column_dimensions['C'].hidden = True
source_wb.close()
return target_workbook
def xls_to_xlsx_libreoffice(xls_file: Path, out_dir: Path):
"""调用LibreOffice命令行静默转换"""
cmd = [
"libreoffice",
"--headless",
"--convert-to", "xlsx",
str(xls_file),
"--outdir", str(out_dir)
]
subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
def batch_convert_xls(input_folder: str):
"""批量转换xls为临时xlsx"""
input_path = Path(input_folder).resolve()
temp_dir = input_path / "temp_xlsx"
temp_dir.mkdir(exist_ok=True)
xls_files = [f for f in input_path.glob("*.xls") if not f.name.startswith("~$")]
if not xls_files:
print("❌ 未找到 .xls 文件")
return []
xlsx_list = []
for file in xls_files:
xls_to_xlsx_libreoffice(file, temp_dir)
xlsx_file = temp_dir / file.with_suffix(".xlsx").name
if xlsx_file.exists():
xlsx_list.append(xlsx_file)
print(f"✅ 转换完成:{file.name}")
return xlsx_list
def batch_merge_xls_to_multi_sheet(input_folder: str, output_file: str = "合并结果.xlsx"):
"""批量合并:一个文件对应一个独立Sheet"""
xlsx_files = batch_convert_xls(input_folder)
if not xlsx_files:
return
# 创建空白工作簿,删除默认Sheet
new_wb = openpyxl.Workbook()
new_wb.remove(new_wb.active)
# 循环复制所有表格
for file in xlsx_files:
try:
sheet_name = file.stem[:30] # 工作表名最长限制30字符
copy_sheet_to_workbook(str(file), new_wb, sheet_name)
print(f"📄 已添加工作表:{sheet_name}")
except Exception as e:
print(f"❌ 处理失败 {file.name}:{str(e)}")
# 保存最终文件
new_wb.save(output_file)
new_wb.close()
print(f"\n🎉 合并完成!文件保存至:{os.path.abspath(output_file)}")
# ===================== 程序入口(仅需修改此处路径) =====================
if __name__ == "__main__":
# 填写你的xls文件夹绝对路径
XLS_FOLDER = "/home/你的用户名/桌面/待合并xls"
# 执行批量合并
batch_merge_xls_to_multi_sheet(
input_folder=XLS_FOLDER,
output_file="多Sheet格式完整合并.xlsx"
)
八、运维排错手册(生产常用)
| 报错现象 | 原因 | 解决方案 |
|---|---|---|
| libreoffice:未找到命令 | 未建立软链接 | 执行文中软链接命令 |
| 离线安装依赖报错 | 依赖缺失 | apt -f install 修复 |
| 隐藏列复制不全 | openpyxl底层BUG | 后置强制隐藏指定列 |
| 转换后表格空白 | WPS占用文件 | 关闭所有表格进程 |
| ARM架构安装失败 | 包架构不匹配 | 使用aarch64专用包 |
九、技术总结
-
国产化麒麟系统禁止使用WPS做命令行转换,格式损坏不可逆;
-
统一采用 LibreOffice 25.8.7.2,x86/ARM双架构完全通用;
-
官方headless转换等同于人工另存为,格式无损,适配老旧xls;
-
针对openpyxl隐藏列BUG,后置强制隐藏是生产环境最优方案;
-
全套代码零修改、跨架构直接迁移,适合内网无外网涉密环境。
十、适用场景
-
政务内网、国产化麒麟服务器、涉密隔离环境;
-
老旧xls存量数据批量格式升级;
-
自动化报表汇总、多文件多Sheet整合;
-
无外网、禁止联网、严格安全管控单位。
💖 原创不易,免费分享,转载请注明出处
如果本文对你有帮助,麻烦点赞+收藏+关注,后续持续更新国产化Linux运维实战教程。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)