這幾天遇到一個BUG,問題很簡單,解決卻花了3、4天,特意記錄下來。

  linux環境下,將預設編碼設定為GBK以後,執行GBK編碼的指令碼,呼叫一個Java的jar包,然後總jar包中返回GBK字串。但是不知道是哪裡出了問題,返回的引數一直是問號亂碼。

  放上指令碼程式碼:

#!/bin/bash
#str="\"$1 $2 $3\""
str="\"http://iap.zh.gmcc.net/WebService/Notify.asmx chenliang3 簡訊測試\""
/flash/system/appr/SafeRun.bin 0 0 "/jre/bin/java -jar /appr/adiap.jar ${str}" 2>&1

  放上除錯時的Java程式碼:

 import java.io.ByteArrayOutputStream;
import java.net.MalformedURLException; import sun.misc.BASE64Decoder; public class text { public static void main(String[] args) throws MalformedURLException, Exception{ //byte[] fullByte1 = new String(str.getBytes("ISO-8859-1"), "UTF-8").getBytes("GBK");
//String fullStr = new String(fullByte1, "GBK"); /* 假設環境是以GBK編碼,將資料解碼成GBK編碼方式,但是任然是???亂碼
* 可能一:資料在編碼之前已經被編碼成utf-8或者ISO-8859-1
* 可能二:在打包過程中,資料被重新編碼
* String temp = new String(args[0].getBytes("GBK"));
* String temp1 = new String(args[0].getBytes("gb2312"));
*/ /* 測試是否打包影響編碼,結果顯示並非打包影響編碼
* String a = new String("簡訊2測試");
* String temp = new String(a.getBytes("GBK"),"utf-8");
* String temp1 = new String(temp.getBytes("utf-8"),"GBK");
* String ios = new String(a.getBytes("GBK"),"ISO-8859-1");
* String ios2 = new String(ios.getBytes("ISO-8859-1"),"GBK");
*
* System.out.print(a+'\r');
* System.out.print(temp+'\r');
* System.out.print(temp1+'\r');
* System.out.print(ios+'\r');
* System.out.print(ios2);
*/ /* 測試轉為了ISO-8859-1還是UTF-8, 未能轉回中文字元,應該轉碼成了UTF-8
* String ios2 = new String(args[0].getBytes("ISO-8859-1"),"GBK");
*/ /*測試獲取到字串的準確編碼,結果為UTF-8
* String whatsencode = getEncoding(args[0]);
* System.out.println(whatsencode);
*/ /* 是否能直接由UTF-8轉為GBK,並未轉回中文字元,任然為問好亂碼
* String ios = new String(args[0].getBytes("UTF-8"),"GBK");
* System.out.print(ios);
*/ /* 詢問大學老師得知,main函式並不會對字串編碼進行變化,
* 那麼會不會是指令碼呼叫jar檔案時會否進行編碼轉換
* 測試Windows下呼叫指令碼是否會?亂碼,指令碼執行需要環境,測試不能,陷入困境
*/ /* 決定在shell指令碼中將字串轉為base64編碼以後傳送過來,在java中解碼完成後傳送回指令碼
* String a = new String("簡訊測試");
* String txt64= getBASE64(a);
* System.out.println(txt64+'\r');
*/ /*
String a = new String("簡訊測試");
String txt64 = getEncoding(a);
System.out.println("-----------------"+'\r');
System.out.println(txt64+'\r');
String en = enUnicode(a);
System.out.println(en);
System.out.println(deUnicode(en));
*/
System.out.println("-----------------"+'\r');
System.out.println(enUnicode("tszQxbLiytQ= 簡訊測試")); /*將接收到的16進位制字串陣列轉為字串再轉為位元組陣列,交換高低位*/ StringBuffer stob = new StringBuffer();
for(int i =0;i<args.length;i++){
System.out.println(args[i]);
if(args[i].length() == 4){
args[i] = swapHexHL(args[i]);
stob. append(args[i]);
}
}
String newStr = stob.toString();
System.out.println(newStr);
String Upstr = newStr.toUpperCase();
String deStr = deUnicode(Upstr);
System.out.println(deStr);
String utfStr = new String(deStr.getBytes("utf-8"));
System.out.println(utfStr); //String newStr = "ccb6c5d0e2b2d4ca000a";
//byte[] newBt = newStr.getBytes("GBK");
//System.out.println(newBt); //System.out.println(deUnicode("B6CCD0C5B2E2CAD40A00"));
/*
String txtde64 = getFromBASE64(args[0]);
System.out.println(txtde64);
*/
}
/*檢測字串編碼*/
public static String getEncoding(String str) {
String encode = "GB2312";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s = encode;
return s;
}
} catch (Exception exception) {
}
encode = "ISO-8859-1";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s1 = encode;
return s1;
}
} catch (Exception exception1) {
}
encode = "UTF-8";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s2 = encode;
return s2;
}
} catch (Exception exception2) {
}
encode = "GBK";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s3 = encode;
return s3;
}
} catch (Exception exception3) {
}
return "";
}
/*對字串進行Base64編碼解碼*/ public static String getBASE64(String s) {
if (s == null) return null;
return (new sun.misc.BASE64Encoder()).encode( s.getBytes() );
}
public static String getFromBASE64(String s) {
if (s == null) return null;
BASE64Decoder decoder = new BASE64Decoder();
try {
byte[] b = decoder.decodeBuffer(s);
return new String(b);
} catch (Exception e) {
return null;
}
} /*將中文與16進位制轉換*/
private static String hexString = "0123456789ABCDEF";
public static String enUnicode(String str) {
// 根據預設編碼獲取位元組陣列
byte[] bytes = str.getBytes();
StringBuilder sb = new StringBuilder(bytes.length * 2);
// 將位元組陣列中每個位元組拆解成2位16進位制整數
for (int i = 0; i < bytes.length; i++) {
sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
}
return sb.toString();
}
public static String deUnicode(String bytes) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(
bytes.length() / 2);
// 將每2位16進位制整陣列裝成一個位元組
for (int i = 0; i < bytes.length(); i += 2)
baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
.indexOf(bytes.charAt(i + 1))));
return new String(baos.toByteArray());
} /*對獲得的16進位制資料進行處理,高低位轉換*/ public static String swapHexHL(String temp){
if (temp == null) return null;
String high = (String) temp.subSequence(0,2);
String low = (String) temp.subSequence(2,4);
String newString = low +high;
return newString;
}
/*去掉XML不認可的字元0x0-0x20*/
public static String delcode(String in) {
StringBuffer out = new StringBuffer(); // Used to hold the output.
char current; // Used to reference the current character.
if (in == null || ("".equals(in)))
return ""; // vacancy test.
for (int i = 0; i < in.length(); i++) {
current = in.charAt(i);
if ((current == 0x9) || (current == 0xA) || (current == 0xD)
|| ((current > 0x20) && (current <= 0xD7FF))
|| ((current >= 0xE000) && (current <= 0xFFFD))
|| ((current >= 0x10000) && (current <= 0x10FFFF))
|| (current < 0x0))
out.append(current);
}
return out.toString().trim();
}
}

  放上從網上找來的亂碼分析:

一個漢字對應兩個問號

在通過GBK從字串獲取位元組陣列時,由於一個Unicode轉換成兩個byte,如果此時用ISO-8859-1或用UTF-8構造字串就會出現兩個問號。

若是通過ISO-8859-1構造可以再通過上面所說的錯上加錯恢復(即再通過從ISO-8859-1解析,用GBK構造);
若是通過UTF-8構造則會產生Unicode字元"\uFFFD",不能恢復,若再通過String-UTF-8〉ByteArray-GBK〉String,則會出現雜碼,如a錕斤拷錕斤拷 編碼過程中錯誤診斷參考
1)一個漢字對應一個問號
在通過ISO-8859-1從字串獲取位元組陣列時,
由於一個Unicode轉換成一個byte,
當遇到不認識的Unicode時,轉換為0x3F,
這樣無論用哪種編碼構造時都會產生一個?亂碼。 2)一個漢字對應兩個問號
在通過GBK從字串獲取位元組陣列時,由於一個Unicode轉換成兩個byte,如果此時用ISO-8859-1或用UTF-8構造字串就會出現兩個問號。
若是通過ISO-8859-1構造可以再通過上面所說的錯上加錯恢復(即再通過從ISO-8859-1解析,用GBK構造);
若是通過UTF-8構造則會產生Unicode字元"\uFFFD",不能恢復,若再通過String-UTF-8〉ByteArray-GBK〉String,則會出現雜碼,如a錕斤拷錕斤拷 3)一個漢字對應三個問號
在通過UTF-8從字串獲取位元組陣列時,由於一個Unicode轉換成三個byte,如果此時用ISO-8859-1構造字串就會出現三個問號;
用GBK構造字串就會出現雜碼,如a涓 枃

  最後還是沒有解決亂碼的問題,而是通過將字串轉16進位制,在Java中轉回的方式實現結果

  放上最後的指令碼程式碼:

 

 #!/bin/bash
str1="\"$1 $2\"" //$1,$2,$3,是執行指令碼時傳送的引數
str2="$3"
str3=`echo ${str2} | od -h`
str4=`echo ${str3:}`
/flash/system/appr/SafeRun.bin "/jre/bin/java -jar /appr/adiap.jar ${str1} ${str4}" >&

一個漢字對應兩個問號

在通過GBK從字串獲取位元組陣列時,由於一個Unicode轉換成兩個byte,如果此時用ISO-8859-1或用UTF-8構造字串就會出現兩個問號。

若是通過ISO-8859-1構造可以再通過上面所說的錯上加錯恢復(即再通過從ISO-8859-1解析,用GBK構造);若是通過UTF-8構造則會產生Unicode字元"\uFFFD",不能恢復,若再通過String-UTF-8〉ByteArray-GBK〉String,則會出現雜碼,如a錕斤拷錕斤拷

編碼過程中錯誤診斷參考1)一個漢字對應一個問號在通過ISO-8859-1從字串獲取位元組陣列時,由於一個Unicode轉換成一個byte,當遇到不認識的Unicode時,轉換為0x3F,這樣無論用哪種編碼構造時都會產生一個?亂碼。

2)一個漢字對應兩個問號
在通過GBK從字串獲取位元組陣列時,由於一個Unicode轉換成兩個byte,如果此時用ISO-8859-1或用UTF-8構造字串就會出現兩個問號。
若是通過ISO-8859-1構造可以再通過上面所說的錯上加錯恢復(即再通過從ISO-8859-1解析,用GBK構造);若是通過UTF-8構造則會產生Unicode字元"\uFFFD",不能恢復,若再通過String-UTF-8〉ByteArray-GBK〉String,則會出現雜碼,如a錕斤拷錕斤拷

3)一個漢字對應三個問號在通過UTF-8從字串獲取位元組陣列時,由於一個Unicode轉換成三個byte,如果此時用ISO-8859-1構造字串就會出現三個問號;用GBK構造字串就會出現雜碼,如a涓 枃