天天看點

jni的中文字元串處理

幾個概念首先要明确:

java内部是使用16bit的unicode編碼(UTF-16)來表示字元串的,無論中文英文都是2位元組;

jni内部是使用UTF-8編碼來表示字元串的,UTF-8是變長編碼的unicode,一般ascii字元是1位元組,中文是3位元組;

c/c++使用的是原始資料,ascii就是一個位元組了,中文一般是GB2312編碼,用兩個位元組來表示一個漢字。

明确了概念,操作就比較清楚了。下面根據字元流的方向來分别說明一下

1、java --> c/c++

這種情況中,java調用的時候使用的是UTF-16編碼的字元串,jvm把這個字元串傳給jni,c/c++得到的輸入是jstring,這個時候,可以利用jni提供的兩種函數,一個是GetStringUTFChars,這個函數将得到一個UTF-8編碼的字元串;另一個是GetStringChars這個将得到UTF-16編碼的字元串。無論那個函數,得到的字元串如果含有中文,都需要進一步轉化成GB2312的編碼。

2、c/c++ --> java

jni傳回給java的字元串,c/c++首先應該負責把這個字元串變成UTF-8或者UTF-16格式,然後通過NewStringUTF或者NewString來把它封裝成jstring,傳回給java就可以了。

如果字元串中不含中文字元,隻是标準的ascii碼,那麼用GetStringUTFChars/NewStringUTF就可以搞定了,因為這種情況下,UTF-8編碼和ascii編碼是一緻的,不需要轉換。

但是如果字元串中有中文字元,那麼在c/c++部分進行編碼轉換就是一個必須了。我們需要兩個轉換函數,一個是把UTF8/16的編碼轉成GB2312;一個是把GB2312轉成UTF8/16。

這裡要說明一下:linux和win32都支援wchar,這個事實上就是寬度為16bit的unicode編碼UTF16,是以,如果我們的c/c++程式中完全使用wchar類型,那麼理論上是不需要這種轉換的。但是實際上,我們不可能完全用wchar來取代char的,是以就目前大多數應用而言,轉換仍然是必須的。

具體的轉換函數,linux和win32都有一定的支援,比如glibc的mbstowcs就可以用來把GB2312編碼轉成UTF16,但是這種支援一般是平台相關的(因為c/c++的标準中并沒有包括這部分),不全面的(比如glibc就沒有提供轉成UTF8的編碼),不獨立的(linux下mbstowcs的行為要受到locale設定的影響)。是以我推薦使用iconv庫來完成轉換。

iconv庫是一個免費的獨立的編碼轉換庫,支援很多平台,多種編碼(事實上,它幾乎可以處理我們所使用的所有字元編碼),而且它的行為不受任何外部環境的影響。iconv在*nix平台上,基本上是預設安裝的。在win32平台上需要額外安裝。

下面提供一個把GB2312編碼的字元串轉換成UTF8編碼的示例

    char* inbuf = new char [n_in + 1];     if (!inbuf) {         iconv_close(c);         return NULL;     }

    strcpy(inbuf, src.c_str());     memset(dst, 0, n_out);

    char* in = inbuf;     char* out = dst;     if (iconv(c, &in, &n_in, &out, &n_out) == (size_t)-1) {         cerr << strerror(errno) << endl;         out = NULL;     }     else {         n_out = strlen(dst);         out = dst;     }

    iconv_close(c);     *nout = n_out;     delete[] inbuf;

    return out; }

補充幾點說明:

1、從jni的接口看,jni提供了UTF16和UTF8兩個系列的字元串處理函數,但是由于jni的文檔中說,jni的内部實作中是用UTF8作為字元串編碼格式的,是以使用UTF8系列比較合适(NewStringUTF/GetStringUTFChars/ReleaseStringUTFChars)

2、使用iconv庫的話,運作環境的設定對于編碼轉換是沒有影響的,但是外層java程式對于字元串的解析依賴于運作環境的locale,是以設定正确的locale對于jni意義不大,但是對整個系統還是必要的。

本文轉自leonpard 51CTO部落格,原文連結:http://blog.51cto.com/leonpard/1172664