2012-04-11 9 views
18

मैं ArrayBuffer वस्तुओं के साथ काम कर रहा हूँ, और मैं उन्हें डुप्लिकेट करना चाहते हैं। हालांकि यह वास्तविक संकेत और memcpy साथ नहीं बल्कि आसान है, मैं जावास्क्रिप्ट में यह करने के लिए किसी भी सरल तरीके से नहीं मिल सका।ऐरेबफर ऑब्जेक्ट की प्रतिलिपि बनाने का सबसे सरल तरीका क्या है?

अभी, यह मैं कैसे कॉपी है मेरी ArrayBuffers:

function copy(buffer) 
{ 
    var bytes = new Uint8Array(buffer); 
    var output = new ArrayBuffer(buffer.byteLength); 
    var outputBytes = new Uint8Array(output); 
    for (var i = 0; i < bytes.length; i++) 
     outputBytes[i] = bytes[i]; 
    return output; 
} 

वहाँ एक खूबसूरत तरीका है?

उत्तर

23

ArrayBuffer समर्थन करने के लिए माना जाता है slice (http://www.khronos.org/registry/typedarray/specs/latest/) ताकि आप, कोशिश कर सकते हैं

buffer.slice(0); 

जो क्रोम 18 नहीं बल्कि फ़ायरफ़ॉक्स में काम करता है 10 या 11. फ़ायरफ़ॉक्स के लिए, आपको इसे मैन्युअल रूप से कॉपी करने की आवश्यकता है। आप बंदर फ़ायरफ़ॉक्स में slice() पैच क्योंकि क्रोम slice() एक मैनुअल प्रतिलिपि से बेहतर प्रदर्शन करेगी सकते हैं। यह कुछ ऐसा दिखाई देगा,

if (!ArrayBuffer.prototype.slice) 
    ArrayBuffer.prototype.slice = function (start, end) { 
     var that = new Uint8Array(this); 
     if (end == undefined) end = that.length; 
     var result = new ArrayBuffer(end - start); 
     var resultArray = new Uint8Array(result); 
     for (var i = 0; i < resultArray.length; i++) 
      resultArray[i] = that[i + start]; 
     return result; 
    } 

तो फिर तुम फोन कर सकते हैं,

buffer.slice(0); 

Chrome और Firefox दोनों में सरणी कॉपी करने के लिए।

+0

परीक्षण किया क्रोम में (इस टिप्पणी के समय 2 9), ऐरेबफर के पास .slice नामक एक विधि नहीं है, लेकिन .subarray (प्रारंभ [, अंत]) इसके बजाए। निश्चित नहीं है कि यह एफएफ में कैसा है। –

+0

ऐसा लगता है कि मेरे उत्तर को उत्पन्न होने के बाद से spec बदल गया है। मैं इसे अद्यतन करने पर काम करूंगा। 'स्लाइस() 'के स्थान पर' subarray() 'नए मानक में है। – chuckj

+1

spec पर फिर से देख रहे हैं, 'ऐरेबफर' में 'टुकड़ा() 'होना चाहिए। टाइप किए गए सरणी (जैसे 'Uint8Array') में 'subarray()' होना चाहिए। उपरोक्त 'ऐरेबफर' के लिए सही है। – chuckj

2

हमम ... यदि यह Uint8Array है जिसे आप टुकड़ा करना चाहते हैं (जो तर्कसंगत है, यह होना चाहिए), यह काम कर सकता है।

if (!Uint8Array.prototype.slice && 'subarray' in Uint8Array.prototype) 
    Uint8Array.prototype.slice = Uint8Array.prototype.subarray; 
2

चकज के उत्तर का तेज और थोड़ा अधिक जटिल संस्करण। बड़े टाइप किए गए सरणी पर ~ 8x कम प्रतिलिपि संचालन का उपयोग करना चाहिए। असल में हम जितना संभव हो उतना 8-बाइट भाग कॉपी करते हैं और फिर शेष 0-7 बाइट कॉपी करते हैं। यह आईई के वर्तमान संस्करण में विशेष रूप से उपयोगी है, क्योंकि इसमें ऐरेबफर के लिए स्लाइस विधि लागू नहीं है।

if (!ArrayBuffer.prototype.slice) 
    ArrayBuffer.prototype.slice = function (start, end) { 
    if (end == undefined) end = that.length; 
    var length = end - start; 
    var lengthDouble = Math.floor(length/Float64Array.BYTES_PER_ELEMENT); 
    // ArrayBuffer that will be returned 
    var result = new ArrayBuffer(length); 

    var that = new Float64Array(this, start, lengthDouble) 
    var resultArray = new Float64Array(result, 0, lengthDouble); 

    for (var i = 0; i < resultArray.length; i++) 
     resultArray[i] = that[i]; 

    // copying over the remaining bytes 
    that = new Uint8Array(this, start + lengthDouble * Float64Array.BYTES_PER_ELEMENT) 
    resultArray = new Uint8Array(result, lengthDouble * Float64Array.BYTES_PER_ELEMENT); 

    for (var i = 0; i < resultArray.length; i++) 
     resultArray[i] = that[i]; 

    return result; 
} 
+0

यह 'का कारण बनता है ArrayBuffer लंबाई शून्य से byteOffset एंड्रॉयड स्टॉक ब्राउज़र में तत्व size.' की एक बहु नहीं है। – duckegg

28

मैं निम्न विधि पसंद करते हैं

function copy(src) { 
    var dst = new ArrayBuffer(src.byteLength); 
    new Uint8Array(dst).set(new Uint8Array(src)); 
    return dst; 
} 
+2

आपके उत्तर की तरह लगता है [चुने हुए से सबसे तेज़] [http://jsperf.com/clone-float32array)। – MaiaVictor

+0

@Viclib, कृपया ध्यान दें कि आपको शायद आईई के लिए फॉलबैक प्रदान करने की आवश्यकता है। – Gleno

+0

अतिरिक्त रूप से नोट करें, विभिन्न प्रकार के लिए यह प्रदर्शन भी भिन्न हो सकता है; फ्लोट 32 की तुलना में Uint8 प्रतियों को मैं याद कर सकता हूं। मुझे लगता है कि सबसे तेज़ इंट 32 था; लेकिन फिर आपके पास डेटा को सही ढंग से गद्दी रखना होगा। YMMV। – Gleno

16

ऐसा लगता है कि बस स्रोत DataView में गुजर एक प्रति करता है:

var a = new Uint8Array([2,3,4,5]); 
var b = new Uint8Array(a); 
a[0] = 6; 
console.log(a); // [6, 3, 4, 5] 
console.log(b); // [2, 3, 4, 5] 

एफएफ 33 और क्रोम 36. में

+1

यह एक अच्छा जवाब है, और यह क्रॉस-ब्राउज़र संगत लगता है। धन्यवाद ! –

+1

वास्तव में, यह स्वीकृत उत्तर से काफी बेहतर है। धन्यवाद! – Nathan

+2

कुछ ध्यान देने योग्य: 'नया Uint8Array (a.buffer) 'नहीं * बफर कॉपी करता है। यह आपकी आवश्यकताओं के आधार पर उपयोगी हो सकता है। यह ऐरेबफर के साथ बुलाए जाने पर वैकल्पिक 'बाइट ऑफसेट' और 'लम्बाई' पैरा भी स्वीकार करता है। यह नोड v6 में नोडजेएस के 'बफर' से (बफर, बाइट ऑफसेट, लंबाई) 'के समान है। – STRML

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

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