ArrayBuffer, String'e ve String'den nasıl dönüştürülür

Renato Mangini

Ham verileri aktarmak için kullanılan ArrayBuffer'lar, WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) ve WebWorkers dahil olmak üzere çeşitli yeni API'ler tarafından kullanılır. Ancak bu işlevler JavaScript dünyasına kısa süre önce eklendiğinden bazen yanlış yorumlanır veya kötüye kullanılır.

Anlamsal olarak, ArrayBuffer yalnızca belirli bir maske aracılığıyla görüntülenen bir bayt dizisidir. ArrayBufferView örneği olan bu maske, baytların içeriğin beklenen yapısıyla eşleşecek şekilde nasıl hizalandığını tanımlar. Örneğin, bir ArrayBuffer'daki baytların 16 bitlik işaretsiz tam sayı dizisini temsil ettiğini biliyorsanız ArrayBuffer'ı bir Uint16Array görünümüne sarmalamak yeterlidir. Ardından, Uint16Array bir tam sayı dizisiymiş gibi parantez söz dizimini kullanarak öğelerini değiştirebilirsiniz:

// suppose buf contains the bytes [0x02, 0x01, 0x03, 0x07]
// notice the multibyte values respect the hardware endianess, which is little-endian in x86
var bufView = new Uint16Array(buf);
if (bufView[0]===258) {   // 258 === 0x0102
    console.log("ok");
}
bufView[0] = 255;    // buf now contains the bytes [0xFF, 0x00, 0x03, 0x07]
bufView[0] = 0xff05; // buf now contains the bytes [0x05, 0xFF, 0x03, 0x07]
bufView[1] = 0x0210; // buf now contains the bytes [0x05, 0xFF, 0x10, 0x02]

ArrayBuffer ile ilgili sık sorulan sorulardan biri, String'ün ArrayBuffer'e ve bunun tersi dönüşümü nasıl yapılacağıdır. ArrayBuffer aslında bir bayt dizisi olduğundan bu dönüşüm, her iki tarafın da dizesindeki karakterlerin bayt olarak nasıl temsil edileceği konusunda anlaşmasını gerektirir. Bu "sözleşmeyi" daha önce görmüş olabilirsiniz: Bu, dizenin karakter kodlamasıdır (ve normal "sözleşme şartları " örneğin Unicode UTF-16 ve iso8859-1'dir). Bu nedenle, sizinle diğer tarafın UTF-16 kodlamasını kabul ettiğini varsayarsak dönüşüm kodu şu şekilde olabilir:

function ab2str(buf) {
    return String.fromCharCode.apply(null, new Uint16Array(buf));
}
function str2ab(str) {
    var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
    var bufView = new Uint16Array(buf);
    for (var i=0, strLen=str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

Uint16Array değerinin kullanıldığını unutmayın. Bu, ArrayBuffer'ların baytlarını 16 bitlik öğeler olarak hizalayan bir ArrayBuffer görünümüdür. Karakter kodlamasını kendisi işlemez. Bu işlem String.fromCharCode ve str.charCodeAt tarafından Unicode olarak gerçekleştirilir.

Bu konuyla ilgili popüler bir StackOverflow sorusunda, dönüşüm için oldukça karmaşık bir çözüm içeren ve çok sayıda oy alan bir yanıt yer alır: Dönüştürücü olarak kullanılacak bir FileReader oluşturun ve dize içeren bir Blob besleyin. Bu yöntem işe yaramasına rağmen okunabilirliği düşüktür ve yavaş olduğu düşünülmektedir. Asılsız şüpheler, insanlık tarihinde birçok hataya yol açtığından bu konuyu daha bilimsel bir yaklaşımla ele alalım. İki yöntemi jsperf ile test ettim ve sonuç şüphelerimi doğruladı. Demoyu buradan inceleyebilirsiniz.

Chrome 20'de, bu makaledeki doğrudan ArrayBuffer değiştirme kodunu kullanmak, FileReader/Blob yöntemini kullanmaktan neredeyse 27 kat daha hızlıdır.