جافا: تحويل السلسلة من وإلى bytebuffer والمشاكل المرتبطة بها

StackOverflow https://stackoverflow.com/questions/1252468

سؤال

أنا أستخدم Java Nio لاتصالات مأخذي، وبروتوكول الخاص بي هو النص، لذلك يجب أن أكون قادرا على تحويل السلاسل إلى Bytebuffers قبل كتابةها إلى Socketchannel، وتحويل Bytebuffers الواردة إلى السلاسل. حاليا، أنا أستخدم هذا الرمز:

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 استثناء، أو ما شابه ذلك، حتى لو كنت أستخدم كائن bytebuffer جديد في كل مرة يتم فيها تحويل. هل أحتاج إلى مزامنة هذه الأساليب؟ أي طريقة أفضل للتحويل بين السلاسل والبايتز؟ شكرا!

هل كانت مفيدة؟

المحلول

تفحص ال CharsetEncoder و CharsetDecoder أوصاف API - يجب أن تتبع تسلسل محدد من مكالمات الأسلوب لتجنب هذه المشكلة. على سبيل المثال، ل CharsetEncoder:

  1. إعادة تعيين التشفير عبر reset الطريقة، ما لم تكن قد استخدمت من قبل؛
  2. استدعاء encode الطريقة الصفرية أو أكثر من المرات، طالما قد تكون المدخلات الإضافية متاحة، تمر false لحجة الإدخال الإلكترونية وملء المخزن المؤقت للإدخال وتنفذ مخزن مؤقت الإخراج بين الدعوات؛
  3. استدعاء encode الطريقة المرة الأخيرة، تمر true وسيطة الإستوفيلية؛ وثم
  4. استدعاء flush الطريقة حتى يتمكن التشفير من تدفق أي حالة داخلية إلى المخزن المؤقت الإخراج.

بالمناسبة، هذا هو نفس النهج الذي أستخدمه ل Nio على الرغم من أن بعض زملائي يقومون بتحويل كل سحر مباشرة إلى بايت في المعرفة، فإنهم يستخدمون فقط ASCII، والتي يمكنني أن أتخيل أنها أسرع.

نصائح أخرى

ما لم تتغير الأمور، فأنت أفضل حالا

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 () إما صحيحا دائما أو كاذبة دائما اعتمادا على حالة استخدامك. في الممارسة العملية، إلا إذا كنت تريد حقا أن تعمل تحت أي ظرف من الظروف، فمن الآمن تحسين الفرع الذي لا تحتاج إليه.

الإجابة بواسطة Adamski هي فكرة جيدة وتصف الخطوات في عملية ترميز عند استخدام طريقة الترميز العامة (التي تأخذ مخزن مؤقت بايت كأحد المدخلات)

ومع ذلك، فإن الطريقة المعنية (في هذه المناقشة) هي متغير من الترميز - تشفير (Charbuffer in). وبعد هذا ال طريقة الراحة التي تنفذ عملية الترميز بأكملها. وبعد (يرجى الاطلاع على مرجع Java Docs في PS)

حسب المستندات، لذلك، لا ينبغي استدعاء هذه الطريقة إذا كانت عملية الترميز قيد التقدم بالفعل (وهو ما يحدث في رمز Zenblender - باستخدام التشفير / فك الترميز الثابت في بيئة متعددة الخيوط).

شخصيا، أحب استخدام السهولة أو الراحة الأساليب (عبر أساليب التشفير / فك التشفير أكثر عمومية) لأنها تسلب العبء عن طريق أداء جميع الخطوات تحت الأغطية.

اقترح Zenblender و Adamski بالفعل خيارات طرق متعددة للقيام بذلك بأمان في تعليقاتهم. سردهم جميعا هنا:

  • قم بإنشاء كائن Encoder / فك تشفير جديد عند الحاجة لكل عملية (غير فعالة حيث يمكن أن يؤدي إلى عدد كبير من الكائنات). أو،
  • استخدم ThreadLocal لتجنب إنشاء تشفير / فك تشفير جديد لكل عملية. أو،
  • مزامنة عملية الترميز / فك التشفير بأكملها (قد لا يفضل ذلك ما لم يكن التضحية ببعض التزامن على ما يرام لبرنامجك)

ملاحظة

مراجع java docs:

  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.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top