在 Java 项目中,资源文件在存储和管理应用程序数据(如本地化字符串、配置设置和其他静态内容)方面起着至关重要的作用。但是,使用资源文件有时会导致编码问题,从而导致文本显示和处理出现问题。
首先,我们来看看编码的定义。它是指使用字节以特定格式表示字符的过程。Java 使用 Unicode 作为其字符集,它支持来自各种语言和脚本的各种字符。
如果您在 Java 项目中遇到编码问题,您可能会看到以下 Java 异常。
java.nio.charset.MalformedInputException: Input length = 1
MalformedInputException
根据有关 Java 8 的 Oracle JavaDoc 的定义,如果输入字节序列对于给定字符集不合法,或者输入字符序列不是合法的 16 位 Unicode 序列,则会出现例外情况。多年来,StackOverflow 等不同社区的在线评论中都提到了这种异常。原则上,我们可以定义三个原因。
编码问题的原因可能是
文本出现乱码或显示不正确:当资源文件未正确编码时,它包含的文本可能会出现乱码或显示不正确。此问题通常表现为一系列奇怪的字符或问号,而不是预期的文本。在处理资源文件时,尤其是那些包含非 ASCII 字符的文件,如果所选的编码格式不兼容,则可能会出现编码问题。
让我们快速看一下以下示例:假设我们想在基于 Java 的 Maven 项目中读取外部资源(文件)。该项目指定了字符编码方案 UTF-8。要指定字符编码方案,我们在 POM 中设置以下内容:
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
为 Java 设置默认(文件)编码的另一种方法是使用环境变量:
JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8"
在这种情况下,我们将遇到异常。解决此问题的一种方法是在文本编辑器中以 Notepad++ 格式打开资源,然后使用代码格式 UTF-8 再次保存文件。MalformedInputException
顺便说一句,如果要过滤属性文件,则必须特别小心。如果筛选的属性文件包含非 ASCII 字符,并且 YOUR 设置为 ISO-8859-1 以外的任何字符,则可能会受到异常的影响。project.build.sourceEncoding
MalformedInputException
当属性文件用作 s 时,所需的编码因 Java 版本而异。在 Java 8 之前(包括 Java 8),这些文件需要使用 ISO-8859-1 编码。ResourceBundle
从 Java 9 开始,属性资源包的首选编码是 UTF-8。它可能适用于 ISO-8859-1,但正如您在 JDK 9 中的国际化增强功能文档中看到的那样,您应该考虑将属性资源包转换为 UTF-8 编码。要定义编码格式,请查看以下示例:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<configuration>
...
<propertiesEncoding>ISO-8859-1</propertiesEncoding>
...
</configuration>
</plugin>
</plugins>
...
</build>
另一种处理异常的方法,我们想要指定要排除的文件,包括代码格式错误的文件。例如,POM 可能如下所示:
<resources>
<resource>
<directory>[your directory]</directory>
<excludes>
<exclude>[non-resource file #1]</exclude>
<exclude>[non-resource file #2]</exclude>
<exclude>[non-resource file #3]</exclude>
...
<exclude>[non-resource file #n]</exclude>
</excludes>
</resource>
...
</resources>
读取或写入问题:不正确的编码也可能导致在读取或写入资源文件时出现问题。读取编码错误的文件可能会导致数据损坏或丢失,而写入编码不兼容的文件可能会产生意外结果或使文件不可用。
让我们来看看一个例子。在此示例中,我们有一个 Java 程序,用于读取目录的基于文本的文件。代码行将如下所示:
BufferedReader reader = Files.newBufferedReader(file,Charset.forName("UTF-8"));
这行代码将创建一个 MalformedInputException 异常。为避免异常,我们重写了这行代码,如下所示:
new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"),"utf-8"));
第一行使用 default action。和 errors 的默认操作是报告它们,而第二行使用 REPLACE 操作。另一种解决方案可能是将字符集更改为 ISO-8859-1。CharsetDecoder
malformed-input
unmappable-character
与外部系统的兼容性: 如果您的 Java 项目与具有特定编码要求的外部系统或 API 交互,则资源文件中的错误编码可能会导致兼容性问题。从这些系统发送或接收的数据可能会被误解,从而导致通信失败或信息处理错误。让我们检查一些有关 Jenkins 服务器的示例:当出现以下情况时,会发生异常:
- Jenkins 主系统设置为接受 UTF-8 字符。
- Jenkins Build Agent 设置为返回 ANSI 字符集。
- 当 Snyk 尝试将 UTF-8 字符从构建代理返回到主系统时,它无法转换为 UTF-8 并显示 .
MalformedInputException
作为解决方案,请设置环境变量并重新启动 Jenkins 代理进程。JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"),"utf-8"));
解决方案策略
- 指定正确的编码: 确保在读取或写入资源文件时指定正确的编码。在大多数情况下,使用 UTF-8 作为默认编码,因为它支持多种字符并且兼容性广泛。但是,如果您正在使用旧系统或有特定要求,请查阅相关文档以确定适当的编码。
- 配置 Build System:如果您的资源文件是构建系统(如 Maven 或 Gradle)的一部分,请确保正确配置编码设置。在构建配置文件中指定所需的编码(例如,pom.xml for Maven),确保它与资源文件中使用的编码一致。
- 验证并转换现有文件:检查现有资源文件以确保它们编码正确。如有必要,使用 native2ascii 或 iconv 等工具将文件从一种编码转换为另一种编码。转换文件时要小心,因为不正确的使用可能会导致进一步的问题。在执行任何转换之前,请务必进行备份。
- 使用编码感知库: 使用资源文件时,利用编码感知库来读取和写入数据。Apache Commons IO 等库提供了处理编码问题的便捷方法,允许您显式指定所需的编码。
- 测试和验证:定期在不同平台和环境中测试和验证您的资源文件,以确保适当的编码兼容性。验证文本是否显示正确,以及是否可以读取和写入文件,而不会出现任何问题。
正确管理资源文件中的编码问题对于 Java 项目至关重要,尤其是在处理具有特定编码要求的多语言应用程序或系统时。通过了解常见的编码问题并实施上述解决方案,您可以确保对资源文件进行准确编码,从而实现无缝文本显示、适当的数据处理并提高与外部系统的兼容性。