从类路径注册字体时抛出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
相关产品推荐
相关产品推荐

