Javascripttypes的数组和字节顺序
我正在使用WebGL来渲染二进制编码的网格文件。 二进制文件是以big-endian格式写出来的(我可以通过在hex编辑器中打开文件或使用fiddler查看networkingstream量来validation这一点)。 当我尝试使用Float32Array或Int32Array读取二进制响应时,二进制被解释为little-endian,我的值是错误的:
// Interpret first 32bits in buffer as an int var wrongValue = new Int32Array(binaryArrayBuffer)[0];
我找不到在http://www.khronos.org/registry/typedarray/specs/latest/中的任何types数组的默认sorting的引用,所以我想知道什么是交易? 我应该假设所有的二进制数据在使用types数组读取时应该是小尾数?
为了解决这个问题,我可以使用一个DataView对象(在前面的链接中讨论)并且调用:
// Interpret first 32bits in buffer as an int var correctValue = new DataView(binaryArrayBuffer).getInt32(0);
DataView函数(如“getInt32”)默认读取big-endian值。
(注意:我已经使用Google Chrome 15和Firefox 8进行testing,它们的行为方式都是一样的)
目前的行为,有些可悲的是,字节序是底层硬件。 几乎所有的台式电脑都是x86的,这意味着小端。 大多数ARM操作系统使用little-endian模式(ARM进程是双端的,并且可以在其中运行)。
之所以会有些悲伤,是因为这意味着几乎没有人会testing他们的代码是否在大端硬件上工作,这会影响到什么,而且整个Web平台是围绕代码在各个实现和平台上统一工作的,这打破了。
从这里http://www.khronos.org/registry/typedarray/specs/latest/ (当该规范完全实现时),您可以使用:
new DataView(binaryArrayBuffer).getInt32(0, true) // For little endian new DataView(binaryArrayBuffer).getInt32(0, false) // For big endian
然而,如果你不能使用这些方法,因为它们没有被实现,你可以随时在头上检查文件的魔法值(几乎每一种格式都有一个魔法值),看你是否需要根据你的endiannes来反转它。
另外,您可以在您的服务器上保存endiannes特定的文件,并根据检测到的主机endiannes使用它们。
仅供参考,您可以使用以下JavaScript函数来确定机器的字节顺序,之后您可以将适当格式的文件传递给客户机(您可以在服务器上存储两个版本的文件,大小写和小端):
function checkEndian() { var arrayBuffer = new ArrayBuffer(2); var uint8Array = new Uint8Array(arrayBuffer); var uint16array = new Uint16Array(arrayBuffer); uint8Array[0] = 0xAA; // set first byte uint8Array[1] = 0xBB; // set second byte if(uint16array[0] === 0xBBAA) return "little endian"; if(uint16array[0] === 0xAABB) return "big endian"; else throw new Error("Something crazy just happened"); }
在你的情况下,你可能不得不重新创build文件的小端,或贯穿整个数据结构,使其小尾数。 使用上述方法的一个扭曲,你可以dynamic地交换字节顺序(不是真的推荐,只有在整个结构是紧凑的types时才有意义,实际上你可以根据需要创build一个交换字节的存根函数):
function swapBytes(buf, size) { var bytes = new Uint8Array(buf); var len = bytes.length; var holder; if (size == 'WORD') { // 16 bit for (var i = 0; i<len; i+=2) { holder = bytes[i]; bytes[i] = bytes[i+1]; bytes[i+1] = holder; } } else if (size == 'DWORD') { // 32 bit for (var i = 0; i<len; i+=4) { holder = bytes[i]; bytes[i] = bytes[i+3]; bytes[i+3] = holder; holder = bytes[i+1]; bytes[i+1] = bytes[i+2]; bytes[i+2] = holder; } } }
其他答案似乎有点过时了,所以这里有一个链接到最新的规范:
http://www.khronos.org/registry/typedarray/specs/latest/#2.1
尤其是:
键入的数组视图types以主机的字节序进行操作。
DataViewtypes对具有指定字节序的数据(大字节或小字节)进行操作。
所以,如果你想读/写Big Endian(networking字节顺序)的数据,请参阅: http : //www.khronos.org/registry/typedarray/specs/latest/#DATAVIEW
// For multi-byte values, the optional littleEndian argument // indicates whether a big-endian or little-endian value should be // read. If false or undefined, a big-endian value is read.