以前一段時間排查一個應用在中文目錄下沒法啓動的問題,查過一個 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