以前一段时间排查一个应用在中文目录下没法启动的问题,查过一个 Equinox 的 Manifest 处理的坑。今天,一个同事在写 Equinox 插件的时候也遇到了相似的问题。这里记录一下 Equinox 里面对 Manifest 中的中文处理的坑。java
先来看一段代码:eclipse
package manifest; import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.jar.Manifest; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.BundleException; public class Test { private static String chineseString = "你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界你好,世界"; public static void main(String[] args) throws IOException, BundleException { File manifestFile = createManifest(); // 使用 ManifestElement 读取 Map<String, String> header = new HashMap<>(); ManifestElement.parseBundleManifest(new FileInputStream(manifestFile), header); System.out.println(header.get("Test-Headers")); } private static File createManifest() throws IOException { Manifest manifest = new Manifest(); manifest.getMainAttributes().putValue("Manifest-Version", "1.0"); // 建立一个带有中文的 Header,MANIFEST.MF 的一行的最大长度是 72 字节,中文在这里会被阶段 manifest.getMainAttributes().putValue("Test-Headers", chineseString); File file = new File("MANIFEST.MF"); if (!file.exists()) { file.createNewFile(); } OutputStream outputStream = new FileOutputStream(file); manifest.write(outputStream); outputStream.flush(); outputStream.close(); return file; } }
这一段代码虽然比较长,可是实际上的内容其实很少,主要作了这几步:ui
ManifestElement
来读取 MANFIEST.MF。上面的这段代码在我本地的执行结果以下:spa
你好,世界你好,世界你好,世界你好,��界你好,世界你好,世界你好,世界你好,世界你��,世界你好,世界你好,世界你好,世界
你们能够看到,中间有几个地方出现了乱码,一样的代码,若是用标准的 JDK 的方式来读取,是不会出现这种状况,为何呢?插件
首先,咱们知道 UTF-8 的中文是占据了三个字节,而 MANIFEST.MF 文件一行的最大长度是 72 个字节,也就是说,若是你的 MANIFEST.MF 中含有中文,那么这个中文的三个字节可能会被截断,出现一部分在上面一行,一部分在下面一行的状况。上面的 MANIFEST.MF 文件就出现了这种状况,能够 cat 这个文件来看一下:code
[~/Desktop/test]$ cat MANIFEST.MF Manifest-Version: 1.0 Test-Headers: 你好,世界你好,世界你好,世界你好,� �界你好,世界你好,世界你好,世界你好,世界你� �,世界你好,世界你好,世界你好,世界
不过,即便这样写入了,若是读取的时候彻底按照字节来读取的话,那也应该没有问题。可是,Equinox 比较特立独行,看下 Equinox 读取 Manifest 的关键代码:图片
做死的 Equinox 将一行读取出来之后直接转成了一个 string,而 byte 在转 string 的时候,若是遇到没法转的字节的话,会用 �
来替代,因而就出现了上面的状况。(关于 �
,能够看 http://en.wikipedia.org/wiki/Specials_(Unicode_block))ip
这个问题除非 Equinox 修复了此 Bug,不然是无解的。只能说在用到 Equinox 的时候,尽可能不要使用中文的 Header 吧。ci