📌 博客标签:#银河麒麟 #国产化 #Python #Excel处理 #LibreOffice #内网离线部署

📌 阅读难度:新手友好、运维开发通用

📌 适用人群:国产化办公、内网运维、Python自动化、政务涉密内网

一、前言(业务真实场景)

1.1 业务背景

目前大量政务、国企、事业单位使用银河麒麟V10国产化操作系统,存在大量老旧 .xls 格式报表。日常工作中存在以下痛点:

  • 内网环境无外网、禁止联网,不能随意安装软件;

  • xls为老旧二进制格式,人工转换效率极低;

  • 表格存在合并单元格、隐藏列、特殊格式、公式,普通转换工具格式丢失;

  • 需要批量汇总:每一个Excel文件保留为独立Sheet,合并至同一个汇总文件。

1.2 硬性业务要求

  1. 禁止人工手动打开表格另存为,必须脚本自动化;

  2. 保留全部表格格式:边框、字体、行高、列宽、隐藏列、合并单元格;

  3. 批量读取xls第一个工作表,一个源文件对应一个Sheet;

  4. 适配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 中文语言包

x86_64 主程序https://downloadarchive.documentfoundation.org/libreoffice/old/25.8.7.2/deb/x86_64/LibreOffice_25.8.7.2_Linux_x86-64_deb.tar.gz

x86_64 中文语言包https://downloadarchive.documentfoundation.org/libreoffice/old/25.8.7.2/deb/x86_64/LibreOffice_25.8.7.2_Linux_x86-64_deb_langpack_zh-CN.tar.gz

ARM64 主程序https://downloadarchive.documentfoundation.org/libreoffice/old/25.8.7.2/deb/aarch64/LibreOffice_25.8.7.2_Linux_aarch64_deb.tar.gz

ARM64 中文语言包https://downloadarchive.documentfoundation.org/libreoffice/old/25.8.7.2/deb/aarch64/LibreOffice_25.8.7.2_Linux_aarch64_deb_langpack_zh-CN.tar.gz

4.2 下载报错解决办法

部分浏览器打开直链提示:当前不支持该文件类型,请尝试其他文件

解决方式:鼠标右键链接 → 另存为,不要直接左键打开。

4.3 解压命令

  1. 下载得到两个 .tar.gz 压缩包,放到麒麟桌面 libreoffice_all_deb_x86 文件夹进行解压安装:
# 【命令注释】cd=切换目录,~/Desktop=桌面,进入存放安装包的文件夹
cd ~/Desktop/libreoffice_all_deb_x86

# 【验证命令】执行后查看文件夹内的文件(可选,确认文件存在)
ls

执行ls后能看到两个.tar.gz文件,说明路径正确。

  1. 解压 主程序 + 中文语言包: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(中文包文件夹)
  1. 合并安装包:两个文件夹内都有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通用离线安装步骤

  1. 批量安装:复制命令直接执行,全程自动安装,红色警告不用管:
# 【命令注释】sudo=获取管理员权限,dpkg -i=安装deb包,*.deb=安装所有安装包
sudo dpkg -i *.deb
  1. 离线修复系统依赖(必做!):麒麟离线安装会缺失依赖文件,执行命令自动修复:
# 【命令注释】自动修复缺失的系统依赖,保证软件正常运行
sudo apt -f install -y

4.5 创建软链接

麒麟系统离线安装后,默认不识别 libreoffice 命令,需要创建软链接(相当于 Windows 快捷方式)。
  1. 查找软件真实路径
# 【命令注释】全局查找 LibreOffice 主程序,屏蔽无用报错
sudo find / -name "soffice" -o -name "libreoffice" 2>/dev/null

✅ 99% 麒麟系统输出固定路径(直接复制备用):

/opt/libreoffice7.3/program/soffice
  1. 创建软链接(直接复制执行)
# 【命令注释】创建软链接,让系统识别 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 小白必看注意事项

  1. 命令中路径不能有空格(麒麟系统偶尔兼容问题)
  2. 源文件不能被 WPS/LibreOffice 打开(文件被占用会转换失败)
  3. 必须先安装 LibreOffice 并配置软链接,否则提示 command not found
  4. 批量转换时,此命令会被 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专用包

九、技术总结

  1. 国产化麒麟系统禁止使用WPS做命令行转换,格式损坏不可逆;

  2. 统一采用 LibreOffice 25.8.7.2,x86/ARM双架构完全通用;

  3. 官方headless转换等同于人工另存为,格式无损,适配老旧xls;

  4. 针对openpyxl隐藏列BUG,后置强制隐藏是生产环境最优方案;

  5. 全套代码零修改、跨架构直接迁移,适合内网无外网涉密环境。

十、适用场景

  • 政务内网、国产化麒麟服务器、涉密隔离环境;

  • 老旧xls存量数据批量格式升级;

  • 自动化报表汇总、多文件多Sheet整合;

  • 无外网、禁止联网、严格安全管控单位。


💖 原创不易,免费分享,转载请注明出处
如果本文对你有帮助,麻烦点赞+收藏+关注,后续持续更新国产化Linux运维实战教程。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐