1、报错信息
使用java.nio.file.Path规范并解析路径,生成文件到本地,部分文件名带中文。提供对外下载文件接口,用于下载这些文件,下载后的文件要显示中文名。本地(windows)开发调试都OK。通过docker容器部署到开发环境(linux集群)后,调用文件生成接口,后台报错,报错信息如下:
Unknown Error:Malformed input or input contains unmappable characters: ????????.xlsx
java.nio.file.InvalidPathException:
Malformed input or input contains unmappable characters: ????????.xlsx
网上找的方案大都需要更新系统级的编码设置,一是比较麻烦,二是不确定会不会影响别人。
若你的需求是,在linux上查看时,文件名也需显示为中文,该文可以不看。
2、大致原因(不深究)
Path解析路径时,使用的getFileSystem().getPath(),获取当前系统并生成路径,查看getPath的说明,其中有一段,大意是在unix上,路径需要符合相应规范,否则会抛InvalidPathException。如果你的linux没有设置相应的语言,中文名就会引发上面的报错。所以可以考虑设置系统语言去解决(自行百度)
3、不想进行系统级设置,临时方案:
使用base62对文件名进行encode后再存储,读取时再decode(不要使用base64,64中有/,会引发路径问题)。
base62可以使用hutool的Base62。hutool没有了解过的可以去百度一下,一个很好用的工具包
public String encodeFileNameByBase62(String fileName) {
if (StrUtil.isBlankIfStr(fileName)) {
throw new ValidationException(ErrorCodeEnum.USER_ERROR_A0400, "待编码的文件名不能为空");
}
return fileName.contains(StrPool.DOT)
? Base62.encode(FileNameUtil.getPrefix(fileName)) + StrPool.DOT + FileNameUtil.extName(fileName)
: Base62.encode(fileName);
}
public String decodeFileNameByBase62(String fileName) {
if (StrUtil.isBlankIfStr(fileName)) {
throw new ValidationException(ErrorCodeEnum.USER_ERROR_A0400, "待解析的文件名不能为空");
}
return fileName.contains(StrPool.DOT)
? Base62.decodeStr(FileNameUtil.getPrefix(fileName)) + StrPool.DOT + FileNameUtil.extName(fileName)
: Base62.decodeStr(fileName);
}