2009-05-18 7 views
20

मुझे java.lang.String से और यूटीएफ -16 बाइट सरणी को एन्कोड/डीकोड करने की आवश्यकता है। बाइट एरे मुझे Byte Order Marker (BOM) के साथ दिए गए हैं, और मुझे बीओएम के साथ बाइट एरे एन्कोड करने की आवश्यकता है।मैं बीओएम के साथ यूटीएफ -16LE बाइट एरे को एन्कोड/डीकोड कैसे करूं?

इसके अलावा, क्योंकि मैं एक Microsoft क्लाइंट/सर्वर से निपट रहा हूं, मैं किसी भी गलतफहमी से बचने के लिए छोटे एंडियन (LE BOM के साथ) में एन्कोडिंग उत्सर्जित करना चाहता हूं। मुझे एहसास है कि बीओएम के साथ इसे बड़े एंडियन काम करना चाहिए, लेकिन मैं विंडोज़ दुनिया में अपस्ट्रीम नहीं तैरना चाहता हूं।

public static byte[] encodeString(String message) { 

    byte[] tmp = null; 
    try { 
     tmp = message.getBytes("UTF-16LE"); 
    } catch(UnsupportedEncodingException e) { 
     // should not possible 
     AssertionError ae = 
     new AssertionError("Could not encode UTF-16LE"); 
     ae.initCause(e); 
     throw ae; 
    } 

    // use brute force method to add BOM 
    byte[] utf16lemessage = new byte[2 + tmp.length]; 
    utf16lemessage[0] = (byte)0xFF; 
    utf16lemessage[1] = (byte)0xFE; 
    System.arraycopy(tmp, 0, 
        utf16lemessage, 2, 
        tmp.length); 
    return utf16lemessage; 
} 

जावा में यह करने के लिए सबसे अच्छा तरीका क्या है:

एक उदाहरण के रूप में, यहाँ एक तरीका है जिसके एक बीओएम के साथ थोड़ा endian में एक java.lang.StringUTF-16 के रूप में encodes है? आदर्श रूप से मैं पूरे बाइट सरणी को एक नए बाइट सरणी में कॉपी करने से बचना चाहता हूं जिसमें शुरुआत में आवंटित दो अतिरिक्त बाइट हैं।

ही इस तरह के एक स्ट्रिंग डीकोड करने के लिए चला जाता है, लेकिन वह बहुत अधिक सरल का उपयोग करके है java.lang.String constructor:

public String(byte[] bytes, 
       int offset, 
       int length, 
       String charsetName) 

उत्तर

27

"UTF-16" चारसेट नाम हमेशा एक बीओएम के साथ सांकेतिक शब्दों में बदलना होगा और या तो का उपयोग कर डेटा को डिकोड होगा बड़ी/छोटी अंतहीनता, लेकिन "यूनिकोडबिग" और "यूनिकोड लिटल" एक विशिष्ट बाइट ऑर्डर में एन्कोडिंग के लिए उपयोगी हैं। बीओएम को मैन्युअल रूप से संभालने के लिए "\ uFEFF" का उपयोग करने के तरीके के लिए कोई बीओएम - see this post के लिए यूटीएफ -16LE या यूटीएफ -16 बीई का उपयोग करें। here को वर्णमाला स्ट्रिंग नामों के कैननिकल नामकरण के लिए या (अधिमानतः) Charset कक्षा देखें। यह भी ध्यान रखें कि केवल limited subset of encodings को समर्थित होने की आवश्यकता है।

+1

धन्यवाद:

यहाँ मैं के साथ समाप्त हो गया है! हालांकि एक और मुद्दा ... "यूटीएफ -16" का उपयोग डेटा को बिग एंडियन के रूप में एन्कोड करता है, जो मुझे संदेह है कि माइक्रोसॉफ्ट डेटा के साथ अच्छा नहीं होगा (भले ही बीओएम मौजूद है)। जावा के साथ बीओएम के साथ यूटीएफ -16LE एन्कोड करने का कोई तरीका? मैं अपने प्रश्न को अद्यतन करने के लिए अपडेट करूंगा कि मैं वास्तव में क्या देख रहा था ... –

+0

उसने दिए गए "इस पोस्ट को देखें" लिंक पर क्लिक करें। असल में, आप अपनी स्ट्रिंग की शुरुआत में एक \ uFEFF वर्ण भरते हैं, और फिर यूटीएफ -16LE में एन्कोड करते हैं, और परिणाम में उचित बीओएम होगा। –

+0

"यूनिकोड लिटल" का उपयोग करें (मान लें कि आपका जेआरई इसका समर्थन करता है - ("\ uEFFF" + "मेरी स्ट्रिंग")। GetBytes ("UTF-16LE") अन्यथा)। हालांकि मुझे आश्चर्य होगा कि माइक्रोसॉफ्ट एपीआई ने बीओएम की उम्मीद की लेकिन बड़े एंडियन डेटा को संभाल नहीं सके - वे अन्य प्लेटफार्मों की तुलना में बीओएम का उपयोग करना पसंद करते हैं। खाली तारों के साथ परीक्षण करें - यदि कोई डेटा नहीं है तो आपको रिक्त सरणी मिल सकती हैं। – McDowell

2
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(string.length() * 2 + 2); 
    byteArrayOutputStream.write(new byte[]{(byte)0xFF,(byte)0xFE}); 
    byteArrayOutputStream.write(string.getBytes("UTF-16LE")); 
    return byteArrayOutputStream.toByteArray(); 

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

मैंने आपकी टिप्पणी देखने से पहले उपरोक्त लिखा था, मुझे लगता है कि एनओओ कक्षाओं का उपयोग करने का उत्तर सही रास्ते पर है। मैं उस पर देख रहा था, लेकिन मैं एपीआई के साथ पर्याप्त परिचित नहीं हूं कि यह जानने के लिए कि आप इसे कैसे करते हैं।

+0

धन्यवाद। इसके अलावा जो मुझे पसंद आया होगा वह स्ट्रिंग.getबाइट्स ("यूटीएफ -16LE") के साथ पूरे बाइट सरणी को आवंटित नहीं करना है - शायद स्ट्रीम को एक इनपुटस्ट्रीम के रूप में लपेटकर, जो मेरे पिछले प्रश्न का बिंदु था: http://stackoverflow.com/questions/837703/how-can-i-get-a-java-io-inputstream-from-a-java-lang-string –

+0

ध्यान दें कि यह कोड वास्तव में स्ट्रिंग के लिए तीन बार पर्याप्त सरणी आवंटित करता है, चूंकि आपके पास ByteArrayOutputStream की आंतरिक सरणी है जिसे कॉल में कॉपी किया गया है .toByteArray()। इसे दोबारा आवंटित करने के लिए इसे वापस पाने का एक तरीका है आउटपुटस्ट्रीमवाइटर में बाइटएरे ऑटपुटस्ट्रीम को लपेटना और उस पर स्ट्रिंग लिखना। फिर आपके पास अभी भी ByteArrayOutputStream की आंतरिक स्थिति और .toByteArray() द्वारा बनाई गई प्रतिलिपि है, लेकिन .getBytes –

+0

से वापसी मूल्य नहीं है ऐसा लगता है कि यदि आप ऐसा करते हैं, तो आउटपुटस्ट्रीमवाइटर प्रतिनिधियों के रूप में आप केवल बाइट सरणी के लिए एक चार सरणी का आदान-प्रदान कर रहे हैं StreamEncoder क्लास में, जो स्ट्रिंग डेटा पुनर्प्राप्त करने के लिए char [] बफर बनाता है। स्ट्रिंग अपरिवर्तनीय है, और एक सरणी का आकार अनावश्यक है, ताकि कॉपी अपरिहार्य प्रतीत हो। मुझे लगता है कि बायोएरे ऑटपुटस्ट्रीम – Yishai

6

डीकोडिंग के लिए आप चरित्र सेट "यूटीएफ -16" का उपयोग कर सकते हैं; जो स्वचालित रूप से प्रारंभिक बीओएम का पता लगाता है। यूटीएफ -16 बीई एन्कोडिंग के लिए, आप "यूटीएफ -16" चरित्र सेट का भी उपयोग कर सकते हैं - जो एक उचित बीओएम लिखेंगे और फिर बड़ी एंडियन सामग्री आउटपुट करेगा।

बीओएम के साथ छोटे एंडियन को एन्कोडिंग के लिए, मुझे नहीं लगता कि आपका वर्तमान कोड बहुत खराब है, यहां तक ​​कि डबल आवंटन के साथ भी (जब तक कि आपके तार वास्तव में राक्षसी नहीं होते)। यदि आप एक बाइट सरणी के साथ सौदा नहीं कर सकते हैं, बल्कि एक java.nio बाइटबफर के साथ सौदा नहीं कर सकते हैं, और java.nio.charset.CharsetEncoder क्लास का उपयोग करें। (जिसे आप Charset.forName ("यूटीएफ -16LE") से प्राप्त कर सकते हैं। NewEncoder())।

+0

पर उस डबल सृजन के साथ निओ को मदद की जानी चाहिए, अच्छी सलाह। –

7

इस तरह आप यह NIO में क्या है:

return Charset.forName("UTF-16LE").encode(message) 
      .put(0, (byte) 0xFF) 
      .put(1, (byte) 0xFE) 
      .array(); 

यह निश्चित रूप से तेजी से माना जाता है, लेकिन मैं नहीं जानता कि कितने सरणियों यह कवर के तहत करता है, लेकिन की बात की मेरी समझ एपीआई यह है कि इसे कम करना है।

+0

यह वास्तव में काम नहीं करता है। Put (0) और put (1) कॉल एन्कोड किए गए संदेश के बाइटबफर के पहले दो बाइट्स को ओवरराइट करता है। – hopia

0

यह एक पुराना सवाल है, लेकिन फिर भी, मुझे अपनी स्थिति के लिए स्वीकार्य उत्तर नहीं मिला। असल में, जावा में बीओएम के साथ यूटीएफ -16LE के लिए अंतर्निर्मित एन्कोडर नहीं है। और इसलिए, आपको अपना खुद का कार्यान्वयन करना होगा।

private byte[] encodeUTF16LEWithBOM(final String s) { 
    ByteBuffer content = Charset.forName("UTF-16LE").encode(s); 
    byte[] bom = { (byte) 0xff, (byte) 0xfe }; 
    return ByteBuffer.allocate(content.capacity() + bom.length).put(bom).put(content).array(); 
} 
संबंधित मुद्दे