जावा: बाइटबफ़र और संबंधित समस्याओं के लिए स्ट्रिंग को परिवर्तित करना


82

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

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अपवाद या इसी तरह फेंक देगा , भले ही मैं एक नया बाइटबफ़र ऑब्जेक्ट का उपयोग कर रहा हूं, जब हर बार रूपांतरण किया जाता है। क्या मुझे इन विधियों को सिंक्रनाइज़ करने की आवश्यकता है? स्ट्रिंग्स और बाइटबफर्स ​​के बीच बदलने का कोई बेहतर तरीका? धन्यवाद!


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

जवाबों:


53

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

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

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


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

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

1
क्या यह काम कर सकता है? नया स्ट्रिंग (bb.array) (), 0, bb.array (), लंबाई, "UTF-8")
17-22 को bentech

38

जब तक चीजें नहीं बदली हैं, आप बेहतर हैं

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);
}

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


14

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

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

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

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

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

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

पी.एस.

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

  1. एनकोड (सुविधा) विधि: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.Charsetuffer%29
  2. सामान्य एनकोड विधि: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java.nio.ByteBuffer,%20boolean% २ ९
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.