Equinox MANIFEST.MF 中文處理 Bug

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

  1. 建立一個內容帶有中文的 MANIFEST.MF 文件。
  2. 寫入 MANIFEST.MF 文件到磁盤上。
  3. 用 Equinox 的 ManifestElement 來讀取 MANFIEST.MF。
  4. 輸出剛纔的帶有中文的 Header

上面的這段代碼在我本地的執行結果以下: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

相關文章
相關標籤/搜索