You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从类路径注册字体时抛出java.nio.BufferUnderflowException异常

解决Jar包运行时注册TTF字体抛出BufferUnderflowException的问题

看起来你遇到的问题根源在于Jar文件中遍历条目时,误把目录条目当成了字体文件来处理——IDE运行时是直接读取文件系统,listFiles()只会返回目录下的文件,不会包含目录本身;但Jar包内的条目会包含目录节点,读取这些无效的流自然会触发异常。

问题分析

当你通过jar.entries()遍历Jar内容时,会拿到所有条目,包括目录本身(比如fonts/这个条目)。尝试用目录的输入流创建Font时,流里没有有效的TTF数据,就会抛出BufferUnderflowException,进而引发FontFormatException。这就是为什么IDE里正常,Jar运行时出错的核心原因。

修复方案

你需要调整Jar条目的过滤逻辑,同时优化资源管理和路径处理,具体做这几个关键修改:

  • 排除目录类型的JarEntry(通过JarEntry.isDirectory()判断)
  • 只保留.ttf后缀的文件,兼容大小写
  • 用try-with-resources自动管理JarFile资源,避免手动关闭遗漏
  • 处理URL路径编码问题(比如路径含空格时的解码)

修改后的代码如下:

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

public static void registerAllFonts(String fontsDir) {
    try {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        final URL codeSourceUrl = FontUtil.class.getProtectionDomain().getCodeSource().getLocation();
        // 处理路径含空格等特殊字符的编码问题
        String jarPath = URLDecoder.decode(codeSourceUrl.toURI().getPath(), StandardCharsets.UTF_8.name());
        final File jarFile = new File(jarPath);

        if (FileUtil.isJarFile(jarFile)) {
            // try-with-resources自动关闭JarFile,无需手动调用close()
            try (JarFile jar = new JarFile(jarFile)) {
                Enumeration<JarEntry> entries = jar.entries();
                ArrayList<JarEntry> jarEntries = Collections.list(entries);
                List<JarEntry> fonts = jarEntries.stream()
                        .filter(entry -> !entry.isDirectory()) // 过滤掉目录条目
                        .filter(entry -> entry.getName().startsWith(fontsDir) 
                                && entry.getName().toLowerCase().endsWith(".ttf")) // 只保留TTF字体文件
                        .collect(Collectors.toList());

                fonts.forEach(entry -> {
                    try {
                        ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, jar.getInputStream(entry)));
                    } catch (FontFormatException | IOException e) {
                        ExceptionUtil.generateErrorLog(e);
                    }
                });
            }
        } else {
            URL url = FontUtil.class.getResource(fontsDir);
            if (url != null) {
                File file = new File(url.toURI());
                if (file.listFiles() != null) {
                    for (File f : file.listFiles()) {
                        // 文件系统下也过滤TTF文件,避免无效文件干扰
                        if (f.getName().toLowerCase().endsWith(".ttf")) {
                            ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, f));
                        }
                    }
                }
            }
        }
    } catch (IOException | FontFormatException | URISyntaxException e) {
        ExceptionUtil.generateErrorLog(e);
    }
}

额外说明

  • 加入.toLowerCase()是为了兼容.TTF大写后缀的字体文件,避免遗漏
  • URLDecoder.decode解决了Jar路径包含空格或特殊字符时的路径解析错误
  • try-with-resources确保JarFile无论是否出现异常都会被正确关闭,避免资源泄漏

这样修改后,Jar运行时就只会处理有效的TTF字体文件,不会再因为读取目录条目而抛出异常了。

内容的提问来源于stack exchange,提问作者Ethan Bacurio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:56:57