2013-03-14 7 views
6

पर कुछ पूर्ण तरीकों को खोना शायद मैं इस गलत तरीके से जा रहा हूं लेकिन मुझे कुछ पूर्णByteBuffer पर विधियां डाल रही हैं।बाइटबफर

यदि आप ByteBuffer पर देखते हैं तो आप देखेंगे कि अधिकांश पुट विधियों में एक पूर्ण और सापेक्ष भिन्नता है।

के अलावा

:

  • ByteBuffer में एक byte सरणी के कुछ हिस्सों लेखन।
  • ByteBuffer को ByteBuffer में लिखना।

.. और मुझे बिल्कुल वही चाहिए।

स्पष्ट है ByteBuffer तरीकों है:

put(byte[] src, int offset, int length) 
put(ByteBuffer src) 

लेकिन कमी है:

put(int index, byte[] src, int offset, int length) 
put(int index, ByteBuffer src) 

मैं कारणों कारण है कि मैं बफर की स्थिति सूचक ले जाने के लिए नहीं करना चाहते हैं, इसलिए मैं केवल उपयोग करना चाहते हैं पूर्ण डाल विधि।

कोई विचार क्यों उन विधियों को छोड़ दिया गया है?

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

आकस्मिक रूप से ByteBuffer आंशिक बाइट सरणी चाल के लिए एक पूर्ण get विधि भी अनुपलब्ध है। लेकिन मुझे वास्तव में इस तरह की एक विधि की जरूरत नहीं है। लेकिन फिर अजीब यह अस्तित्व में नहीं है।

+0

बस एक फॉलो-अप। यह http://thesoftwarelife.blogspot.dk/2009/10/java-bytebuffer-annoyances.html पाया है जो लगभग एक ही चीज़ के बारे में शिकायत कर रहा है। – peterh

+1

मैं तर्क दूंगा कि पूर्ण विधियां सापेक्ष लोगों की तुलना में अधिक उपयोगी और महत्वपूर्ण हैं। अगर मैं उस एपीआई को फिर से डिजाइन कर रहा था, तो मैं सभी पदों को छोड़ दूंगा, फ्लिप, रिवाइंड, मार्क, रीसेट, और इसी तरह और केवल मेमोरी एक्सेस प्रदान करने पर ध्यान केंद्रित करूँगा, इसे मूल रूप से एक हेवीवेट सरणी के रूप में छोड़कर सी 'यूनियन' विशेषताएं। – Boann

+1

@ बोआन - ऐसा ही होगा। बिल्कुल जिस तरह से मैं इसके बारे में सोचता हूं। – peterh

उत्तर

4

एक तरीका यह तरीकों की जरूरत है पाने के लिए एक दूसरे ByteBuffer उसी स्मृति साझा करने, ताकि आप मूल की स्थिति बदले बिना अपनी स्थिति को बदल सकते हैं के लिए है।

दुर्भाग्यवश, slice विधि स्थिति पैरामीटर नहीं लेती है; इसके बजाय यह मूल बफर की वर्तमान स्थिति का उपयोग करता है। तो तुम नहीं कर सकते:

dstBuffer.slice(100).put(srcBuffer); 

यहाँ कुछ विचार कर रहे हैं, कोई विशेष क्रम में छोड़कर यह आदेश मैं उन्हें के बारे में सोचा है:

  • यदि यह जिस तरह से आप बफर का उपयोग कर रहे साथ फिट बैठता है, आप slice() के साथ बफर की एक प्रति तैयार कर सकते हैं और उस स्थिति को तब रख सकते हैं जब आपको मूल स्थिति से स्वतंत्र स्थिति में डेटा डालना होगा।

  • स्थिति में आप पर पूर्ण रखना चाहते हैं हमेशा अधिक से अधिक या मूल बफर की स्थिति सूचक के बराबर है, तो आप कर सकते हैं:

    dstBuffer.slice().position(desiredPosition - dstBuffer.position()).put(srcBuffer); 
    

कि काम नहीं करेगा एक पर डाल करने के लिए दुर्भाग्यवश, पहले की स्थिति, चूंकि टुकड़े की स्थिति को नकारात्मक होने की अनुमति नहीं है। संपादित करें: कोई बात नहीं, मैं duplicate विधि के बारे में भूल गया। @ बोरिस ब्रोड्स्की का महान जवाब देखें।

  • आप सीधे बाइट बफ़र्स का उपयोग नहीं कर रहे हैं, तो System.arraycopy आसान और तेज़ है:

    System.arraycopy(
        srcBuffer.array(), srcBuffer.arrayOffset() + srcBuffer.position(), 
        dstBuffer.array(), dstBuffer.arrayOffset() + desiredPosition, 
        srcBuffer.remaining() 
    ); 
    
  • तो समवर्ती पहुंच होना आवश्यक नहीं है, तो आप अस्थायी रूप से बफर की स्थिति को बदल सकते हैं जब आप की जरूरत एक पूर्ण डाल करने के लिए और बाद में इसे वापस रखो। आप समवर्ती पहुंच की आवश्यकता है, लेकिन धागा विवाद कम है, तो आप बफर के इस्तेमाल के सभी सिंक्रनाइज़ कर सकते हैं (हो सकता है स्पष्ट है, लेकिन पूर्णता के लिए शामिल है):

    synchronize (lock) { 
        int originalPosition = dstBuffer.position(); 
        dstBuffer.position(desiredPosition); 
        dstBuffer.put(srcBuffer); 
        dstBuffer.position(originalPosition); 
    } 
    
  • अन्य विचारों से कोई भी आप के लिए काम करते हैं, आप कर सकते हैं बफर हैक। यह गंदा है, लेकिन यहाँ एक उदाहरण है:

    private static final sun.misc.Unsafe UNSAFE; 
    static { 
        Object result = null; 
        try { 
         Class<?> klass = Class.forName("sun.misc.Unsafe"); 
         for (Field field : klass.getDeclaredFields()) { 
          if (field.getType() == klass && 
           (field.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) == 
            (Modifier.FINAL | Modifier.STATIC)) { 
           field.setAccessible(true); 
           result = field.get(null); 
           break; 
          } 
         } 
        } catch (Throwable t) {} 
        UNSAFE = result == null ? null : (sun.misc.Unsafe)result; 
    } 
    
    private static final Field ADDRESS_FIELD; 
    static { 
        Field f; 
        try { 
         f = Buffer.class.getDeclaredField("address"); 
         f.setAccessible(true); 
        } catch (NoSuchFieldException | SecurityException e) { 
         f = null; 
        } 
        ADDRESS_FIELD = f; 
    } 
    
    
    public static void absolutePut(ByteBuffer dstBuffer, int dstPosition, ByteBuffer srcBuffer) { 
        if (!srcBuffer.isDirect()) { 
         absolutePut(dstBuffer, dstPosition, 
          srcBuffer.array(), srcBuffer.arrayOffset() + srcBuffer.position(), 
          srcBuffer.remaining()); 
         return; 
        } 
    
        if (UNSAFE != null && ADDRESS_FIELD != null && dstBuffer.isDirect()) { 
         try { 
          long dstAddress = (long)ADDRESS_FIELD.get(dstBuffer) + dstPosition; 
          long srcAddress = (long)ADDRESS_FIELD.get(srcBuffer) + srcBuffer.position(); 
          UNSAFE.copyMemory(srcAddress, dstAddress, srcBuffer.remaining()); 
         } catch (IllegalAccessException e) { 
          throw new RuntimeException(e); 
         } 
        } else { 
         // fallback to basic loop 
         for (int i = srcBuffer.position(); i < srcBuffer.limit(); i++) { 
          dstBuffer.put(dstPosition + i, srcBuffer.get(i)); 
         } 
        } 
    } 
    
    public static void absolutePut(ByteBuffer dstBuffer, int dstPosition, byte[] src, int srcOffset, int length) { 
        if (UNSAFE != null && ADDRESS_FIELD != null && dstBuffer.isDirect()) { 
         try { 
          long dstAddress = (long)ADDRESS_FIELD.get(dstBuffer) + dstPosition; 
          UNSAFE.copyMemory(
           src, UNSAFE.arrayBaseOffset(byte[].class) + srcOffset, 
           null, dstAddress, 
           length); 
         } catch (IllegalAccessException e) { 
          throw new RuntimeException(e); 
         } 
        } else { 
         // fallback to System.arraycopy 
         System.arraycopy(
          src, srcOffset, 
          dstBuffer.array(), dstBuffer.arrayOffset() + dstPosition, 
          length); 
        } 
    } 
    

मैं प्रत्यक्ष और अप्रत्यक्ष बफ़र्स की घोला जा सकता है के साथ इस कोड कुछ न्यूनतम परीक्षण दिया है और यह ठीक लग रहा है। यदि प्रतिबिंब तकनीक विफल हो जाती है (उदा।, क्योंकि आप एक एप्लेट सुरक्षा सैंडबॉक्स में हैं या जावा कार्यान्वयन संगत नहीं है) तो यह सादे तरीकों से वापस आ सकता है।

+0

यह दिलचस्प है कि आप सहमति के साथ बहुत चिंतित हैं। यद्यपि बाइटबफर का एक साथ उपयोग करने का इरादा नहीं है, और इस बात की कोई गारंटी नहीं है कि इसके किसी भी तरीके, यहां तक ​​कि पूर्ण प्राप्त, थ्रेड सुरक्षित हैं, हम अभी भी कुछ विशेष अनुप्रयोगों में कुछ समरूपता मान सकते हैं और बफर का उपयोग कर सकते हैं। (अधिकांश ऐप्स बाइटबफर का उपयोग एक साथ नहीं करते हैं) – ZhongYu

+0

@ बोआन। उसके लिये आपका धन्यवाद। मैं खुद टुकड़ा मार्ग का पीछा करने का एक प्रकार था, लेकिन मैं एक अरब बाइटबफर के साथ समाप्त होता हूं जिसे सभी को कहीं भी रहना पड़ता है। मुझे अभी भी पहेली क्या है कि इन तरीकों की कमी क्यों है। शायद कुछ ऐसा है जो मैंने याद किया है। और हाँ, मैं दुर्भाग्य से ऐसी स्थिति में हूं जहां मैं प्रत्यक्ष बफर का उपयोग कर रहा हूं, अन्यथा मैं सहमत हूं कि 'System.arraycopy() 'समाधान अच्छा होगा। – peterh

2
static void put(ByteBuffer buffer, int index, ByteBuffer src) 
{ 
    int p0 = buffer.position(); 
    buffer.position(index); 
    buffer.put(src); 
    buffer.position(p0); 
} 
+0

क्षमा करें, समाधान नहीं। आप गंतव्य की स्थिति सूचक को स्थानांतरित कर रहे हैं (क्योंकि आप 'buffer.position (अनुक्रमणिका)' करते हैं) जिसका अर्थ है कि आपके समाधान में पूर्ण विधि विधि की विशेषताएं नहीं हैं।(जो कि यह स्थिति सूचक को अपरिवर्तित छोड़ देता है) – peterh

+0

@ nolan6000: आप गंतव्य की स्थिति सूचक को ठीक उसी स्थान पर डाल रहे हैं जहां यह शुरू हुआ, जो वास्तव में इस समस्या का एक बिल्कुल मान्य समाधान है। इस कानूनी समाधान के लिए +1। –

+0

@ nolan6000 uh? स्थिति को इसके मूल मूल्य पर वापस बदल दिया गया है। – ZhongYu

3

मेरी राय में, उन विधियों को छोड़ दिया गया, क्योंकि ऐसा कोई अन्य तरीका मौजूद नहीं है। "बाइट" सहित प्राइमेटिव लेने वाले पूर्ण तरीकों का समूह है, लेकिन प्राइमेटिव्स के सर को लेकर कोई पूर्ण विधि नहीं है।

समाधान हो सकता है:

((ByteBuffer)buffer.duplicate().position(index)).put(src, offset, length); 
((ByteBuffer)buffer.duplicate().position(index)).put(otherByteBuffer); 
+0

यद्यपि इसमें थोड़ा ऑब्जेक्ट निर्माण ओवरहेड है, लेकिन यह सबसे अच्छा समाधान है जिसे मैं मानता हूं। यह छोटा और प्यारा है और नौकरी करता है। – Boann

+0

सहमत हैं। यह मीठा लग रहा है। मुझे परीक्षण करना होगा कि ऑब्जेक्ट सृजन का प्रदर्शन प्रभाव नगण्य है या नहीं। यदि इस समाधान का उपयोग करते हुए मैं उपरोक्त निष्पादित करता हूं जो प्रत्येक लिखने के लिए मैं चाहता हूं। बहुत सारे ओवरहेड की तरह लगता है लेकिन कभी-कभी हम (या अधिक सही ढंग से) प्रदर्शन समस्याओं को देखते हैं जहां कोई भी नहीं है। :-)। पारितोषिक के लिए धन्यवाद। – peterh

0

यहाँ है कि मैं क्या एक निरपेक्ष थोक get() के लिए उपयोग कर रहा हूँ है: put() के लिए

// Perform a bulk get() that doesn't modify the buffer 
public void get(ByteBuffer buf, int position, byte[] dest, int off, int len) { 
    if (buf.hasArray()) 
     System.arraycopy(buf.array(), buf.arrayOffset() + position, dest, off, len); 
    else if (len < 256) {  // 256 is a wild guess TODO: performance testing 
     while (len-- > 0) 
      dest[off++] = buf.get(position++); 
    } else 
     ((ByteBuffer)buf.duplicate().position(position)).get(dest, off, len); 
} 

ऐसा ही एक approache काम करता है।

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