2009-08-09 10 views
70

मैं अपने सॉकेट कनेक्शन के लिए जावा एनआईओ का उपयोग कर रहा हूं, और मेरा प्रोटोकॉल टेक्स्ट आधारित है, इसलिए मुझे स्ट्रिंग्स को बाइटबफर में सॉकेट चैनल में लिखने से पहले कनवर्ट करने में सक्षम होना चाहिए, और इनकमिंग बाइटबफर को स्ट्रिंग्स में वापस कनवर्ट करें। वर्तमान में, मैं इस कोड का उपयोग कर रहा हूँ:जावा: बाइटबफर और उससे संबंधित समस्याओं से स्ट्रिंग कनवर्ट करना

public static Charset charset = Charset.forName("UTF-8"); 
public static CharsetEncoder encoder = charset.newEncoder(); 
public static CharsetDecoder decoder = charset.newDecoder(); 

public static ByteBuffer str_to_bb(String msg){ 
    try{ 
    return encoder.encode(CharBuffer.wrap(msg)); 
    }catch(Exception e){e.printStackTrace();} 
    return null; 
} 

public static String bb_to_str(ByteBuffer buffer){ 
    String data = ""; 
    try{ 
    int old_position = buffer.position(); 
    data = decoder.decode(buffer).toString(); 
    // reset buffer's position to its original so it is not altered: 
    buffer.position(old_position); 
    }catch (Exception e){ 
    e.printStackTrace(); 
    return ""; 
    } 
    return data; 
} 

इस समय के सबसे अधिक काम करता है, लेकिन मैं सवाल है कि अगर यह पसंद किया गया (या सरल) जिस तरह से इस रूपांतरण की प्रत्येक दिशा क्या करना है, या अगर कोई करने के लिए एक और तरीका है प्रयत्न। कभी-कभी, और प्रतीत होता है कि यादृच्छिक रूप से, encode() और decode() पर कॉल java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END अपवाद, या इसी तरह के फेंक देगा, भले ही मैं एक बार एक नया बाइटबफर ऑब्जेक्ट का उपयोग कर रहा हूं, एक रूपांतरण हो। क्या मुझे इन तरीकों को सिंक्रनाइज़ करने की आवश्यकता है? स्ट्रिंग्स और बाइटबफर के बीच कनवर्ट करने का कोई बेहतर तरीका? धन्यवाद!

+0

यह अपवाद के पूर्ण स्टैक ट्रेस को देखने में मदद करेगा। –

उत्तर

49

बाहर चेक CharsetEncoder और CharsetDecoder एपीआई विवरण - आप विधि का एक विशिष्ट अनुक्रम का पालन करना चाहिए कॉल इस समस्या से बचने के लिए। उदाहरण के लिए, CharsetEncoder के लिए:

  1. एनकोडर reset विधि के माध्यम से, रीसेट जब तक यह पहले इस्तेमाल नहीं किया गया है;
  2. encode विधि शून्य या अधिक बार, जब तक अतिरिक्त इनपुट उपलब्ध हो, false को एंडऑफ इनपुट तर्क के लिए पास करना और इनपुट बफर भरना और इनवॉक्शंस के बीच आउटपुट बफर को फ़्लश करना;
  3. encode विधि को एक अंतिम बार आमंत्रित करें, 0Oको एंडऑफ इनपुट तर्क के लिए पास करना; और फिर
  4. flush विधि को आमंत्रित करें ताकि एन्कोडर आउटपुट बफर में किसी भी आंतरिक स्थिति को फ्लश कर सके।

वैसे, यह एक ही दृष्टिकोण मैं NIO के लिए उपयोग कर रहा हूँ, हालांकि मेरे साथियों में से कुछ ज्ञान वे केवल ASCII का उपयोग कर रहे है, जो मैं कल्पना कर सकते हैं में एक बाइट के लिए सीधे प्रत्येक चार परिवर्तित कर रहे हैं शायद तेजी से होता है है।

+2

बहुत बहुत धन्यवाद, यह बहुत उपयोगी था! मैंने पाया कि मेरे पास कई रूपांतरण थे जो मेरे रूपांतरण कार्यों को एक साथ कॉल करते थे, भले ही मैंने इसे अनुमति देने के लिए डिज़ाइन नहीं किया था। मैंने charset.newEncoder()। Encode() और charset.newDecoder()। Decode() को कॉल करके इसे ठीक किया है यह सुनिश्चित करने के लिए कि मैं प्रत्येक बार एक नया एन्कोडर/डिकोडर का उपयोग कर रहा हूं ताकि समवर्ती मुद्दों से बचने के लिए, या उन वस्तुओं पर सिंक्रनाइज़ करने की आवश्यकता न हो, जो मेरे मामले में सार्थक डेटा साझा नहीं करता है। मैंने कुछ परीक्षण भी चलाए और हर बार newEncoder()/newDecoder() का उपयोग करने में कोई मापनीय प्रदर्शन अंतर नहीं मिला! – DivideByHero

+2

कोई समस्या नहीं है। आप प्रत्येक बार नए एन्कोडर्स/डिकोडर्स बनाने से बच सकते हैं लेकिन थ्रेडलोकल का उपयोग कर अभी भी थ्रेड सुरक्षित रह सकते हैं, और आलसी रूप से आवश्यक रूप से एक समर्पित एन्कोडर/डिकोडर प्रति थ्रेड बनाते हैं (यह मैंने किया है)। – Adamski

+1

यह काम कर सकता है? नया स्ट्रिंग (बीबी.एरे(), 0, बीबी.एरे() लंबाई, "यूटीएफ -8") – bentech

11

अदाम्सकी द्वारा उत्तर एक अच्छा एक है और एक एन्कोडिंग ऑपरेशन में चरणों का वर्णन करता है जब सामान्य एनकोड विधि (कि आदानों की एक के रूप में एक बाइट बफर लेता है)

हालांकि का उपयोग कर, सवाल में विधि (इस में चर्चा) एनकोड का एक रूप है - एन्कोड (चारबफर इन)। यह सुविधा विधि है जो संपूर्ण एन्कोडिंग ऑपरेशन लागू करती है। (कृपया पुनश्च में जावा डॉक्स संदर्भ देखें)

डॉक्स के अनुसार, इस विधि इसलिए लागू नहीं किया जाना चाहिए अगर कोई एन्कोडिंग कार्रवाई जारी (जो क्या ZenBlender के कोड में क्या हो रहा है में पहले से ही है - स्थिर एनकोडर का उपयोग कर/एक बहु थ्रेडेड पर्यावरण में डीकोडर)।

व्यक्तिगत रूप से, मैं सुविधा विधियों (अधिक सामान्य एन्कोड/डिकोड विधियों पर) का उपयोग करना पसंद करता हूं क्योंकि वे कवर के तहत सभी चरणों का पालन करके बोझ दूर करते हैं।

जेनब्लेंडर और एडमस्की ने पहले से ही अपनी टिप्पणियों में सुरक्षित तरीके से ऐसा करने के कई विकल्प सुझाए हैं।उन्हें यहां सूचीबद्ध करें:

  • प्रत्येक ऑपरेशन के लिए आवश्यक होने पर एक नया एन्कोडर/डिकोडर ऑब्जेक्ट बनाएं (कुशल नहीं है क्योंकि यह बड़ी संख्या में ऑब्जेक्ट्स का कारण बन सकता है)। या,
  • प्रत्येक ऑपरेशन के लिए नए एन्कोडर/डिकोडर बनाने से बचने के लिए थ्रेडलोकल का उपयोग करें। या,
  • पूरे एन्कोडिंग/डिकोडिंग आपरेशन सिंक्रनाइज़ करें (यह प्राथमिकता नहीं दी जा सकता है जब तक कि कुछ संगामिति त्याग अपने कार्यक्रम के लिए ठीक है)

पी.एस.

जावा डॉक्स संदर्भ:

  1. एनकोड (सुविधा) विधि: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer%29
  2. जनरल एनकोड विधि: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java.nio.ByteBuffer,%20boolean%29
16

जब तक चीजें बदल गई है, तो आप

public static ByteBuffer str_to_bb(String msg, Charset charset){ 
    return ByteBuffer.wrap(msg.getBytes(charset)); 
} 

public static String bb_to_str(ByteBuffer buffer, Charset charset){ 
    byte[] bytes; 
    if(buffer.hasArray()) { 
     bytes = buffer.array(); 
    } else { 
     bytes = new byte[buffer.remaining()]; 
     buffer.get(bytes); 
    } 
    return new String(bytes, charset); 
} 
साथ बेहतर कर रहे हैं

आमतौर पर buffer.hasArray() होगा अपने उपयोग के मामले के आधार पर हमेशा सत्य या हमेशा झूठी रहें। अभ्यास में, जब तक कि आप वास्तव में किसी भी परिस्थिति में काम नहीं करना चाहते हैं, तब तक उस शाखा को अनुकूलित करना सुरक्षित है जिसकी आपको आवश्यकता नहीं है।

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