银河麒麟系统下WPS公文字体安装与缓存排查
刚接手一台银河麒麟桌面系统的办公机时我遇到的第一个问题是同一份公文在原来的环境里打开是标题小标宋、正文仿宋_GB2312到了新机器上标题变成黑体、正文变成宋体行距和字距全部乱掉打印出来完全不是那么回事。文档本身没有任何改动问题出在系统里没有这些公文字体。这类问题在国产化替代的办公场景里非常普遍银河麒麟系统 WPS Office的组合装好之后系统自带的字体只有那么几套仿宋_GB2312、楷体_GB2312、小标宋这些公文必备字体一个都没有WPS 找不到就按自己的规则回落于是一份排版严谨的公文被翻译成了另一种样子。这篇内容就是围绕银河麒麟系统下给 WPS 装公文字体这件事展开的。我会讲清楚字体在系统里到底是怎么被找到的、装到哪个目录才不会白装、装完之后 WPS 为什么有时候还是不认、以及批量给一屋子机器部署时怎么省事。适合三类人看刚换到国产化系统、被公文格式折腾过的办公人员负责单位终端运维、需要一次性解决一批机器的技术人员以及想弄明白 fontconfig 这套机制到底怎么运转的爱好者。不需要你懂太多 Linux命令可以直接抄。1. 先把问题想明白字体为什么装了等于没装1.1 WPS 找字体的真实顺序很多人以为字体装上就完事实际上 WPS 渲染一段文字要经过两道关。第一道是文档层文件里存的是字体名比如仿宋_GB2312注意这是一个字符串不是一个文件路径。第二道是系统层需要有人把这个字符串翻译成具体的字形文件这个翻译官就是 fontconfig。WPS 启动时会向 fontconfig 要一份字体清单把每个字体族名family name登记在自己的字体下拉框里。打开文档时它拿文档里记录的字体名去这份清单里比对比对上了就用比对不上就走替换逻辑。替换逻辑的默认行为很粗暴中文一律往默认的宋体或者黑体上靠英文往默认无衬线字体上靠。这就解释了一个很常见的困惑明明字体文件已经拷进机器了为什么还不变因为文件存在不等于族名被登记。fontconfig 只扫描特定目录只认特定格式还需要缓存刷新才会生效。三者缺一不可任何一环掉链子结果都是装了等于没装。我见过最典型的翻车现场是有人把字体文件放在下载目录里然后打开 WPS 期待它自动出现。这个目录从来就不在扫描范围里放了半年也不会有反应。1.2 银河麒麟的字体目录与缓存机制银河麒麟桌面版走的是 Debian 系的目录规范fontconfig 会按优先级扫描几个固定位置。搞清这张表后面所有的操作就都有依据了。目录位置作用范围优先级适用场景~/.local/share/fonts当前用户高个人临时用、无管理员权限~/.fonts当前用户高旧约定老教程常用仍然有效/usr/local/share/fonts全系统中管理员自装字体推荐/usr/share/fonts/truetype/全系统中发行版包管理的字体/opt/.../wps-office/office6/fonts仅 WPS应用内应急不推荐长期用优先级这一列值得多说一句。当同一个族名存在多个文件时用户目录下的会盖住系统目录下的。这个机制有时候是帮手有时候是坑如果某个同事在自己家目录里放了一份旧版仿宋你在系统里装了新版他那台机器上永远是旧的字形而且你怎么查系统目录都查不出问题。后面排查章节会专门讲这个。缓存这块fontconfig 会在~/.cache/fontconfig下生成二进制缓存文件记录每个字体的族名、字重、支持的字符集等信息。系统启动或者执行fc-cache时才会重建。你拷完文件不刷缓存fontconfig 的清单里就没有新增项WPS 自然也看不到。这是装完必须刷缓存的根本原因不是玄学。1.3 三个高频误区先避开第一个误区是改后缀就行。有人拿到一个字体文件发现扩展名不认识直接改成.ttf。fontconfig 判断格式靠的是文件头魔数不是后缀改后缀除了让文件名好看一点没有任何作用反而会让人误以为已经处理过了。第二个误区是只装进 WPS 私有目录。把字体塞到 WPS 安装目录下的 fonts 子目录确实能让 WPS 用上但同一台机器上的其他办公软件、截图工具、PDF 阅读器依然是缺字状态。而且 WPS 升级或者重装这个目录可能被覆盖字体一夜之间全没了。这种做法只适合临时救急。第三个误区是字体装得越多越好。有人图省事把能找到的字体全拷进去几百个字体文件。后果是 WPS 启动时扫描清单明显变慢字体下拉框长得没法用而且同名不同版本的字体互相打架排出来的版式忽大忽小。字体这东西够用就行。2. 动手前的准备格式、来源与环境确认2.1 字体格式怎么选ttf、ttc、otf 的取舍公文字体常见的三种容器格式处理方式不太一样先弄清楚再动手能省不少事。格式特点兼容性建议.ttf单字体TrueType 轮廓最好首选问题最少.ttc字体集合一个文件含多个字重好宋体、黑体常见此格式直接装.otfOpenType可能是 CFF 轮廓较好能用但老版本 WPS 偶有渲染异常.ttc需要特别说明一下。它内部包含多个 facefontconfig 扫描时会一次性登记多个族名。有人用fc-scan查看.ttc发现输出好几段以为出错了其实正常。装的时候整个文件拷过去就行不需要拆分。.otf的问题主要出现在一些较老版本的 WPS 上CFF 轮廓的渲染偶尔会出现笔画变细、字重不对的情况。如果你手头的公文字体有 ttf 和 otf 两个版本优先用 ttf。这不是绝对规则但在实际部署里能少掉很多解释成本。还有一个细节文件名本身不影响识别。字体叫什么名字取决于文件内部嵌入的 name 表跟文件名毫无关系。所以你把FS_GB2312.TTF改名成fangsong.ttf族名依然是仿宋_GB2312。反过来说两个不同字体文件如果被改成同一个文件名后拷进去的会覆盖前面的族名却还是各自的这种混乱很难排查。我的习惯是保留原始文件名不改。2.2 字体来源与授权这地方最容易栽跟头公文字体绝大多数属于商业字库是有版权的。这一点必须先说清楚因为我在运维现场见过太多次从某个网盘随手下一包字体的操作单位层面是有合规风险的。正规的获取路径有三条。第一条是单位统一采购的字库授权通常会给一个介质或者授权包里面按字体族分好目录这种最省心直接用。第二条是随正版办公软件附带的字体资源安装介质里往往带了一部分。第三条是使用开源替代字体比如思源宋体、思源黑体、文泉驿系列这些是明确可以自由使用的。开源替代这条路要说清楚它的局限能解决显示不缺字的问题但不能完全满足严格的公文格式要求。因为公文格式标准里对正文、标题使用的字体是有明确指向的替代字体在字形上终归有差异正式发文场景下还是得用指定的那几套。所以替代方案适合内部草稿、日常沟通正式文稿还得走授权渠道。这个判断我一般会提前跟使用方讲明白免得后面返工。提示拿到字体包之后先别急着拷用fc-scan看一眼族名确认是不是你要的那一套。市面上同名不同版的字体很多族名一样但字形有细微差别的情况不少见。2.3 装之前先确认环境和现状动手前花两分钟做基线记录后面出问题时有对照。# 看架构x86_64 还是 aarch64跟字体选择无关但便于记录环境 uname -m # 看系统版本 cat /etc/kylin-build 2/dev/null || cat /etc/os-release # 当前已装的中文字体数量和清单 fc-list :langzh | wc -l fc-list :langzh family | sort -u # 看 WPS 装在哪 which wpsfc-list :langzh family | sort -u这条最有用它会列出当前系统认识的所有中文字体族名。装之前跑一遍存下来装完再跑一遍对比新增了哪些一目了然。这比在 WPS 的字体下拉框里翻要靠谱得多因为下拉框里显示的可能是本地化名称跟族名对不上。顺便确认一下 WPS 的版本。不同版本的字体处理逻辑有差异尤其是一些较老的版本对.otf支持不好提前知道能少走弯路。3. 三步装字体复制、授权、刷缓存3.1 全局装还是单用户装先做个决定这个选择影响后续所有操作先定下来。对比项全局安装单用户安装目录/usr/share/fonts/truetype/下自建子目录~/.local/share/fonts权限要求需要 root普通用户即可生效范围本机所有用户、所有应用仅当前用户适合场景办公机、公用终端、批量部署个人笔记本、无管理员权限维护成本统一升级方便各自为政容易版本混乱公用办公机一律选全局。原因很实际这类机器经常多人轮换使用账号换来换去字体装在某个人的家目录里换个人登录就又缺字了然后又来报故障。全局装一次所有人都不受影响。单用户安装适合那种没有管理员权限、只是想临时看一下文档的场景。操作上把路径换掉即可后面的刷缓存步骤一样。3.2 复制、权限与属主一步到位我推荐用install命令而不是cp因为它能一次性把权限和属主都设好少敲两条命令也少一个出错的机会。# 建一个专门的目录别跟系统自带字体混在一起方便日后整体卸载 sudo mkdir -p /usr/share/fonts/truetype/gongwen # 把字体文件拷进去权限 644属主 root sudo install -m 644 -o root -g root /path/to/fonts/*.TTF /usr/share/fonts/truetype/gongwen/ sudo install -m 644 -o root -g root /path/to/fonts/*.ttc /usr/share/fonts/truetype/gongwen/几个细节值得单独讲。目录要自建并起个有意义的名字。我习惯用gongwen一眼能看出是公文类字体。日后要卸载或者整体替换rm -rf这一个目录就干净了不会误伤系统字体。如果直接把文件撒在/usr/share/fonts/truetype/根下时间一长根本分不清哪些是后加的。权限必须是 644目录必须是 755。字体文件如果带可执行位某些安全检查工具会报警如果是 600其他用户读不到就只有装字体的那个人能用又回到单用户状态了。install -m 644一次搞定。属主设为 root。普通用户拥有的系统字体文件在启用了一些文件保护策略的环境里可能被判定为异常虽然不影响使用但会给后续的安全扫描添麻烦。文件名里的中文和空格要处理。有些字体包里的文件名带中文命令行里直接cp *可能出问题。稳妥的做法是先ls看一眼必要时用引号包起来或者先重命名成英文再拷。文件名不影响族名识别重命名是安全的。如果字体包是分目录组织的比如一个目录放宋体、一个目录放楷体可以用 find 一次性处理sudo find /path/to/fonts -type f \( -iname *.ttf -o -iname *.ttc -o -iname *.otf \) \ -exec install -m 644 -o root -g root {} /usr/share/fonts/truetype/gongwen/ \;-iname而不是-name是因为不少字体包的扩展名是大写的.TTF用小写匹配会漏掉一半文件。这个坑我踩过装完之后发现只有一部分字体生效查了半天才发现是大小写问题。3.3 刷新缓存并验证别跳过这步拷完文件不刷缓存等于没装。这一步是硬性的。# 只刷新建的这个目录速度快 sudo fc-cache -f -v /usr/share/fonts/truetype/gongwen # 或者全量刷新稳妥但慢一点 sudo fc-cache -f -v-f是强制重建-v是输出详细过程。加上-v能看到它扫描了哪些文件、登记了哪些族名出问题时这是第一手线索。刷完之后立刻验证三个层次的检查# 第一层文件有没有被扫到 fc-list | grep -i gongwen # 第二层族名有没有登记上 fc-list :langzh family | sort -u # 第三层指定名字能不能匹配到 fc-match FangSong_GB2312 fc-match KaiTi_GB2312fc-match这条最关键。它模拟的正是应用程序要字体时的行为你给它一个名字它告诉你最终会返回哪个字体文件。如果返回的是你装的那个文件说明链路通了如果返回的是某个宋体说明没匹配上得回去查族名到底叫什么。不确定族名的时候直接扫文件fc-scan --format %{family}\n /usr/share/fonts/truetype/gongwen/FS_GB2312.TTF输出可能是多行第一行通常是英文族名后面是本地化名称。WPS 文档里存的可能是中文名也可能是英文名两个都要能被匹配到才算稳。为了便于对照这里整理一张常见公文字体的族名参照表。注意文件名只是举例实际以你手上的授权介质为准。文档中的字体名常见英文族名常见文件名标识典型用途仿宋_GB2312FangSong_GB2312FS_GB2312、SIMFANG公文正文楷体_GB2312KaiTi_GB2312KT_GB2312、SIMKAI公文中二级标题宋体SimSunSIMSUN通用正文黑体SimHeiSIMHEI公文一级标题小标宋FZXiaoBiaoSong-B05SFZXBSJW公文大标题4. WPS 这边还得收拾一下4.1 彻底退出不是关窗口字体装好、缓存刷完很多人直接切回已经开着的 WPS 看效果发现没变化就以为装失败了。实际上 WPS 的字体清单是启动时加载的进程不退出就不会重新读取。关掉文档窗口不等于退出进程。WPS 桌面版有三个主要进程文字wps、表格et、演示wpp另外还有云服务相关的后台进程。只要进程还在字体清单就是旧的。# 先正常保存关闭所有文档然后确认进程 pgrep -a wps pgrep -a et pgrep -a wpp # 确认没有未保存内容后结束进程 pkill -f wps pkill -f et pkill -f wpp更稳妥的方式是通过菜单完全退出或者在任务栏图标上右键选择退出。用pkill之前一定确认文档都保存了不然丢失内容得不偿失。重新启动 WPS打开字体下拉框输入仿宋看有没有出现仿宋_GB2312。出现了就成功了一大半。4.2 名字对不上时用 fontconfig 做别名映射有一种情况很磨人字体装好了fc-match也能匹配到但文档里存的字体名跟你装的族名差一点点比如文档里写仿宋你装的叫FangSong_GB2312WPS 就是认不出来依然回落。这种时候不用改文档改系统的匹配规则更省事。fontconfig 支持别名映射可以把一个名字指向另一个名字。新建用户级配置文件~/.config/fontconfig/fonts.conf?xml version1.0? !DOCTYPE fontconfig SYSTEM fonts.dtd fontconfig match targetpattern test qualany namefamily string仿宋/string /test edit namefamily modeassign bindingsame stringFangSong_GB2312/string /edit /match match targetpattern test qualany namefamily string楷体/string /test edit namefamily modeassign bindingsame stringKaiTi_GB2312/string /edit /match /fontconfig写完之后刷新用户缓存fc-cache -f -v fc-match 仿宋fc-match 仿宋现在应该返回仿宋_GB2312 的文件路径。bindingsame这个属性不能省它表示强绑定不加的话只是弱建议实际匹配时可能被其他规则盖过去。这个方案的好处是改在系统层所有应用一起受益不用在每个软件里单独设置。如果要做全局生效把这段内容放到/etc/fonts/conf.d/下命名成类似99-gongwen-alias.conf注意用 99 开头保证优先级靠后。部分版本的 WPS 在选项里也提供了字体替换功能可以手动把缺失字体映射到已有字体。菜单位置各版本有差异一般在工具-选项里找。功能上跟 fontconfig 别名是等效的但只在 WPS 内部生效。我个人的偏好是优先用 fontconfig一次配置全局通用重装 WPS 也不受影响。4.3 导出 PDF 时记得嵌入字体字体装好、版式正常之后还有一个环节容易忽略把文档发给别人时对方没装这些字体打开还是变样。解决办法是导出 PDF 时嵌入字体。WPS 的 PDF 导出对话框里通常有字体嵌入相关选项确保勾选。导出完成后可以验证一下# 查看 PDF 里嵌入的字体清单 pdffonts 你的文件.pdf输出的表格里有一列是字体名如果显示的是具体字体名而不是Type3之类说明嵌入成功。pdffonts属于 poppler-utils 包系统里不一定预装没有的话也不影响日常使用只是少了一个验证手段。这一步在实际工作里价值很高。公文流转的最后一公里往往是对方打开看看如果对方机器上没装公文字体你这边排得再准也是白费。嵌入字体之后PDF 在任何机器上打开都是同一个样子。5. 常见问题排查速查5.1 现象与原因对照表下面这张表是我这些年遇到过的典型情况汇总按出现频率排序。现象可能原因排查命令处理方式WPS 字体框里看不到新字体缓存没刷 / 进程没重启fc-list | grep 字体名刷缓存 彻底退出 WPSfc-list有但 WPS 没有用户目录有旧版覆盖fc-list | grep -i 同名删掉用户目录的旧文件字体名对字形不对同名不同版本冲突fc-match -s 字体名看排序清掉优先级高的旧文件版式行距整体偏移字体度量差异对比原文档字体设置确认用的是同一版本字体装完系统变卡字体数量过多fc-list | wc -l精简到必要的几十个某目录怎么都不生效目录不在扫描范围fc-list | grep 目录名挪到标准目录5.2 用户目录旧字体覆盖系统字体的排查这个问题排查起来最费时间因为所有的检查看起来都正常。系统目录里的字体是最新的缓存也刷了fc-match返回的却是旧文件。原因就是 1.2 节提到的优先级用户目录下的字体优先级高于系统目录。某台机器上如果有人以前往~/.fonts或~/.local/share/fonts里放过同名旧字体那么无论系统目录怎么更新这个用户看到的永远是旧的。# 按优先级列出所有匹配结果 fc-match -s FangSong_GB2312 | head -10-s会把所有匹配项按优先级排序输出第一个就是实际生效的那个。看它的路径如果在家目录下问题就找到了。处理方式有两种把用户目录里的旧文件删掉或者把新版字体也放进用户目录覆盖。前者更彻底后者见效快。如果是多人共用的机器建议统一清理一遍所有人的家目录一次性解决。5.3 字形对但排版不对的情况字体装对了文字能正常显示但整篇文档的行距、字距、每页行数跟原稿有偏差。这通常不是字体安装的问题而是字体版本差异。同一套字体不同版本的字形度量ascent、descent、行高等参数可能有细微差别。公文的版式是精确到行距磅值和每行字数的度量差一点点累积到整页就明显了。特别是公文格式要求每页固定行数、每行固定字数这种精确排版对字体度量非常敏感。# 查看字体的度量信息 fc-scan --format %{family} ascent%{ascent} descent%{descent}\n 字体文件对比一下新旧字体的数值差异大就说明是版本问题。解决办法只有一个用跟原稿完全一致的字体版本。这也是为什么批量部署时要把字体版本固定下来不能这台机器一个版本、那台机器另一个版本。还有一类排版问题是字体缺字。某些公文字体只覆盖了 GB2312 范围内的字符遇到生僻字、异体字、特殊符号就会回落到其他字体视觉上表现为个别字字形不一样。这种情况只能靠补装覆盖面更广的字体或者把这些字替换成常用字。5.4 系统安全策略的干扰银河麒麟桌面版带有一套安全管理组件其中有些策略会限制应用读取非标准目录的文件。正常情况下/usr/share/fonts属于标准位置不会拦截。但如果把字体放在家目录的自定义目录里又正好开了比较严格的文件保护策略就可能出现文件明明在就是读不到的情况。判断方法很简单用fc-list看得到用普通用户身份读文件也没问题但应用里就是不生效。这时候可以去看一下安全中心的相关策略配置或者干脆把字体挪到标准目录绕开这个变量。6. 批量部署与长期维护的做法6.1 一个可以直接复用的部署脚本给一屋子机器装字体一台台手敲不现实也不利于版本统一。下面这个脚本我用了很多次逻辑简单容错够用。#!/bin/bash # 用法: sudo ./install-gongwen.sh /path/to/fonts set -e SRC_DIR$1 DST_DIR/usr/share/fonts/truetype/gongwen if [ -z $SRC_DIR ] || [ ! -d $SRC_DIR ]; then echo 用法: $0 字体目录 exit 1 fi if [ $(id -u) -ne 0 ]; then echo 需要 root 权限运行 exit 1 fi mkdir -p $DST_DIR count0 while IFS read -r -d f; do install -m 644 -o root -g root $f $DST_DIR/ count$((count 1)) done (find $SRC_DIR -type f \ \( -iname *.ttf -o -iname *.ttc -o -iname *.otf \) -print0) if [ $count -eq 0 ]; then echo 源目录里没找到字体文件检查一下路径和扩展名 exit 1 fi echo 已安装 $count 个字体文件到 $DST_DIR fc-cache -f $DST_DIR /dev/null 21 echo 缓存已刷新当前中文字体清单 fc-list :langzh family | sort -u echo echo 抽查匹配结果 for name in FangSong_GB2312 KaiTi_GB2312 SimHei; do printf %-20s - %s\n $name $(fc-match -f %{file} $name) done脚本本身没什么花哨的几个设计点说明一下。用-print0加read -d 处理文件名。字体包里带空格、带中文、带特殊字符的情况很常见普通的for f in $(find ...)遇到空格就断开了这个组合能稳妥处理。装之前先判空。如果源目录路径敲错了find找不到任何文件脚本会静默成功让人以为装完了实际什么都没干。加上数量检查能避免这种假成功。装完自动抽查。最后那段fc-match循环是给自己看的三个关键字体是不是都指向了正确路径一眼就知道有没有翻车。6.2 字体精简与版本固化部署完不是结束长期维护上有两件事值得做。第一件是控制数量。系统里中文字体超过一两百个之后WPS 启动扫描会明显变慢字体下拉框也难用。我一般会把非必要的字体清掉只留公文字体、系统必需字体和一两套通用字体。清理的时候注意别删发行版包管理的字体在/usr/share/fonts/truetype/下由 dpkg 管理的目录只删自己建的目录里的内容。# 看哪些字体是自己装的 ls -la /usr/share/fonts/truetype/gongwen/ # 整体移除 sudo rm -rf /usr/share/fonts/truetype/gongwen sudo fc-cache -f -v第二件是版本固化。同一个单位里所有机器的公文字体版本必须一致否则同一份文档在不同机器上打开行距可能差那么一两磅打印出来就对不齐。做法很简单把通过验证的字体包放到共享位置所有机器都从这个包里安装不要各自去找。前面那个脚本可以配合一个固定的字体包使用每次部署都跑同一个源版本自然统一。我在实际使用中发现这套流程里最容易出问题的环节不是技术操作而是以为装好了。拷完文件不刷缓存、刷完缓存不重启 WPS、重启了不验证每一步跳过都可能留下隐患而且往往要等到几天后打正式文件时才发现。所以我把验证命令写进了脚本装完自动跑一遍输出结果直接截图存档后面出了问题也有个对照。多花两分钟省掉后面半天的来回确认。