Ubuntu服务器Groovy/Java中含变音符号文件exists()返回false问题
Linux下Groovy/Java处理含变音符号文件时exists()返回false的解决方法
问题重现
测试代码
def f1 = new File('/var/lib/jenkins/test/') def files = [:] f1.listFiles().each { files.put(it.name, it.getAbsoluteFile().exists()) } println files println 'file.encoding:' + System.getProperty('file.encoding')
执行结果
Verderblichkeit.docx:true Gefa��hrlichkeit.docx:false file.encoding:"iso-8859-1"
系统文件列表(ls -al输出)
drwxr-xr-x 2 jenkins jenkins 4096 Jan 5 18:17 . drwxr-xr-x 66 jenkins jenkins 12288 Jan 5 18:16 .. -rw-r--r-- 1 jenkins jenkins 98035 Jan 5 18:16 Gefährlichkeit.docx -rw-r--r-- 1 jenkins jenkins 277515 Jan 5 18:17 Verderblichkeit.docx
环境信息
- Java版本:Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
- 实际场景:数据库获取的文件路径可被Nginx正常访问,但Grails应用中
File.exists()返回false,已尝试设置file.encoding=UTF-8但无效。
原因分析
- 旧File类的编码缺陷:Java 8的
File类依赖sun.jnu.encoding参数处理文件名编码,而非file.encoding。仅设置file.encoding无法解决文件名的转码问题,导致变音符号文件名被错误转码,进而exists()无法匹配真实文件。 - 系统locale与JVM编码不匹配:Linux系统文件名默认以UTF-8存储,但JVM若使用ISO-8859-1等非UTF-8编码处理文件名,会出现乱码和匹配失败。
解决方案
1. 改用Java NIO的Path/Files类替代File类
NIO API直接与文件系统原生文件名交互,不受JVM编码参数影响,能正确处理Unicode字符。重写后的测试代码:
import java.nio.file.* def dir = Paths.get('/var/lib/jenkins/test/') def files = [:] Files.list(dir).forEach { path -> def fileName = path.getFileName().toString() files.put(fileName, Files.exists(path)) } println files println 'file.encoding:' + System.getProperty('file.encoding')
2. 配置JVM的文件名编码参数
在应用启动时(如Jenkins启动脚本、Grails启动参数)添加以下参数:
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
sun.jnu.encoding:控制JVM处理文件名的编码,必须设为与系统文件系统一致的UTF-8。file.encoding:控制文本文件的编码,需同步设置以避免其他文本处理问题。
3. 确保系统locale为UTF-8
执行locale命令检查当前系统语言环境,若输出的LANG或LC_ALL不是UTF-8格式,需修改配置:
- 编辑
/etc/default/locale文件,添加或修改:LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 - 重启系统或应用,使配置生效。
内容的提问来源于stack exchange,提问作者Dirk27
相关产品推荐
相关产品推荐

