2012-07-03 13 views
7

निम्नलिखित कोडजावा बग? Utf8 एन्कोडिंग में अतिरिक्त शून्य बाइट क्यों?

public class CharsetProblem { 
public static void main(String[] args) { 
    //String str = "aaaaaaaaa"; 
    String str = "aaaaaaaaaa"; 
    Charset cs1 = Charset.forName("ASCII"); 
    Charset cs2 = Charset.forName("utf8"); 

    System.out.println(toHex(cs1.encode(str).array())); 
    System.out.println(toHex(cs2.encode(str).array())); 

} 

public static String toHex(byte[] outputBytes) { 

    StringBuilder builder = new StringBuilder(); 

    for(int i=0; i<outputBytes.length; ++i) { 
     builder.append(String.format("%02x", outputBytes[i])); 
    } 

    return builder.toString(); 
} 
} 

रिटर्न

61616161616161616161 
6161616161616161616100 

अर्थात UTF8 एन्कोडिंग रिटर्न अतिरिक्त बाइट। यदि हम कम एस लेते हैं, तो हमारे पास कोई अतिरिक्त बाइट नहीं होगा। यदि हम अधिक से अधिक लेते हैं तो हम अधिक से अधिक बाइट प्राप्त कर सकते हैं।

क्यों?

कोई इसे कैसे काम कर सकता है?

उत्तर

6

आप केवल बैकिंग सरणी नहीं प्राप्त कर सकते हैं और इसका उपयोग कर सकते हैं। बाइटबफर के पास capacity, position and a limit है।

System.out.println(cs1.encode(str).remaining()); 
System.out.println(cs2.encode(str).remaining()); 

पैदा करता है:

10 
10 

ऐसा करें:

public static void main(String[] args) { 
    //String str = "aaaaaaaaa"; 
    String str = "aaaaaaaaaa"; 
    Charset cs1 = Charset.forName("ASCII"); 
    Charset cs2 = Charset.forName("utf8"); 

    System.out.println(toHex(cs1.encode(str))); 
    System.out.println(toHex(cs2.encode(str))); 
} 

public static String toHex(ByteBuffer buff) { 
    StringBuilder builder = new StringBuilder(); 
    while (buff.remaining() > 0) { 
    builder.append(String.format("%02x", buff.get())); 
    } 
    return builder.toString(); 
} 

यह पैदा करता है उम्मीद:

61616161616161616161 
61616161616161616161 
6

आप मान रहे हैं कि ByteBuffer के लिए बैकिंग सरणी सामग्री को पकड़ने के लिए सही आकार है, लेकिन यह जरूरी नहीं है। वास्तव में, सामग्री को सरणी के पहले बाइट पर भी शुरू करने की आवश्यकता नहीं है! ByteBuffer के लिए एपीआई का अध्ययन करें और आप समझेंगे कि क्या हो रहा है: सामग्री arrayOffset() द्वारा लौटाए गए मान पर शुरू होती है, और अंत limit() द्वारा लौटाया जाता है।

2

जवाब पहले से ही दिया गया है, लेकिन जैसा कि मैंने भाग गया एक ही समस्या में, मुझे लगता है कि यह हो सकता है अधिक जानकारी प्रदान करने के लिए उपयोगी रहें:

cs1.encode(str).array() या cs2.encode(str).array() का उपयोग करके बाइट सरणी लौटाई गई उस समय बाइटबफर को आवंटित पूरे सरणी का संदर्भ देता है। सरणी की क्षमता वास्तव में उपयोग की जाने वाली चीज़ों से अधिक हो सकती है। केवल उपयोग किए गए हिस्से को पुनर्प्राप्त करने के लिए आपको निम्न की तरह कुछ करना चाहिए:

ByteBuffer bf1 = cs1.encode(str); 
ByteBuffer bf2 = cs2.encode(str); 
System.out.println(toHex(Arrays.copyOf(bf1.array(), bf1.limit()))); 
System.out.println(toHex(Arrays.copyOf(bf2.array(), bf2.limit()))); 

यह आपके द्वारा अपेक्षित परिणाम उत्पन्न करता है।

संबंधित मुद्दे