2013-02-19 4 views
3

JavaScript에 Uint8Array 배열이있는 경우 어떻게 마지막 4 바이트를 가져 와서 int로 변환 할 수 있습니까? C#을 사용하면 다음과 같이 할 수 있습니다.배열의 마지막 4 바이트를 정수로 변환하는 방법?

int count = BitConverter.ToInt32(array, array.Length - 4); 

JavaScript를 사용하여 이와 다른 방법이 있습니까?

+0

@ cIph3r : [예] (https : //developer.mozilla.(Chrome 및 Safari, Opera, IE10 및 Android) (http :// ko/org/ko-ko/docs/JavaScript/Typed_arrays/Uint8Array) – Bergi

+0

@Bergi 괜찮 았지만 firefox – cIph3r

+1

@ clph3r, /caniuse.com/#feat=typedarrays) .... –

답변

7

액세스를 ArrayBuffer 밑에 그 바이트 슬라이스 새로운 TypedArray 만들기 :

var u8 = new Uint8Array([1,2,3,4,5,6]); // original array 
var u32bytes = u8.buffer.slice(-4); // last four bytes as a new `ArrayBuffer` 
var uint = new Uint32Array(u32bytes)[0]; 

TypedArray 커버되지 않으면 전체 버퍼는 약간 복잡 할 뿐이지 만 약간은 복잡해야합니다.

var startbyte = u8.byteOffset + u8.byteLength - Uint32Array.BYTES_PER_ELEMENT; 
var u32bytes = u8.buffer.slice(startbyte, startbyte + Uint32Array.BYTES_PER_ELEMENT); 

두 경우 모두 작동합니다.

데이터 유형에 대한 기본 버퍼의 정렬 경계에 맞게 원하는 바이트가있는 경우 (예 : 기본 버퍼의 4-8 바이트의 32 비트 값을 원할 경우) slice()으로 바이트 복사를 피할 수 있습니다 @ Bergi의 대답처럼 view 생성자에 byteoffset을 제공하면됩니다.

다음은 원하는 모든 오프셋의 스칼라 값을 가져야하는 매우 가볍게 테스트 된 함수입니다. 가능한 경우 복사하지 않습니다.

function InvalidArgument(msg) { 
    this.message = msg | null; 
} 

function scalarValue(buf_or_view, byteOffset, type) { 
    var buffer, bufslice, view, sliceLength = type.BYTES_PER_ELEMENT; 
    if (buf_or_view instanceof ArrayBuffer) { 
     buffer = buf_or_view; 
     if (byteOffset < 0) { 
      byteOffset = buffer.byteLength - byteOffset; 
     } 
    } else if (buf_or_view.buffer instanceof ArrayBuffer) { 
     view = buf_or_view; 
     buffer = view.buffer; 
     if (byteOffset < 0) { 
      byteOffset = view.byteOffset + view.byteLength + byteOffset; 
     } else { 
      byteOffset = view.byteOffset + byteOffset; 
     } 
     return scalarValue(buffer, view.byteOffset + byteOffset, type); 
    } else { 
     throw new InvalidArgument('buf_or_view must be ArrayBuffer or have a .buffer property'); 
    } 
    // assert buffer instanceof ArrayBuffer 
    // assert byteOffset > 0 
    // assert byteOffset relative to entire buffer 
    try { 
     // try in-place first 
     // only works if byteOffset % slicelength === 0 
     return (new type(buffer, byteOffset, 1))[0] 
    } catch (e) { 
     // if this doesn't work, we need to copy the bytes (slice them out) 
     bufslice = buffer.slice(byteOffset, byteOffset + sliceLength); 
     return (new type(bufslice, 0, 1))[0] 
    } 
} 

이처럼 사용합니다 :

// positive or negative byte offset 
// relative to beginning or end *of a view* 
100992003 === scalarValueAs(u8, -4, Uint32Array) 
// positive or negative byte offset 
// relative to the beginning or end *of a buffer* 
100992003 === scalarValue(u8.buffer, -4, Uint32Array) 
+0

+1, 매우 좋습니다. 그러나 'u8'이 버퍼에 오프셋이있는보기 인 경우 특수하게 처리해야합니다. – Bergi

5

예가 있습니까? 나는 이것을 할 것이라고 생각한다 :

var result = ((array[array.length - 1]) | 
       (array[array.length - 2] << 8) | 
       (array[array.length - 3] << 16) | 
       (array[array.length - 4] << 24)); 
+0

'[255,255,255,255]'를 사용하면 어떤 이유로이 코드를 사용하여'-1'이됩니다. – Jespertheend

+0

@Jespertheend 서명이 '-1'인 결과입니다. 결과를 부호없는 값 ('4294967295')으로 변환하려면 부호없는 오른쪽 시프트 연산자'>>> 0'을 추가하십시오. – SammieFox

+0

흠, 그건 의미가 있습니다. – Jespertheend

3

조금 우아하지만, 수동으로 엔디안을 기반으로 할 수 있다면.

리틀 엔디안 :

var count = 0; 
// assuming the array has at least four elements 
for(var i = array.length - 1; i >= array.length - 4; i--) 
{ 
    count = count << 8 + array[i]; 
} 

빅 엔디안 :이 다른 데이터로 확장 할 수

var count = 0; 
// assuming the array has at least four elements 
for(var i = array.length - 4; i <= array.length - 1 ; i++) 
{ 
    count = count << 8 + array[i]; 
} 

편집 길이 : 내 오타

+1

은'.length'가 아니어야합니다.'.Length' – 0x499602D2

1

을 지적 데이비드 덕분에 Uint32Array를 만드는 것이 더 효율적이어야합니다. 523,210 동일한 ArrayBuffer에 직접 32- 비트 수에 :

var uint8array = new Uint8Array([1,2,3,4,5,6,7,8]); 
var uint32array = new Uint32Array(
        uint8array.buffer, 
        uint8array.byteOffset + uint8array.byteLength - 4, 
        1 // 4Bytes long 
       ); 
return uint32array[0]; 
+0

두 번째 인수가 새로운 뷰의 길이의 배수가 아니면 같은 버퍼에 다른 유형의 새로운 뷰를 생성 할 수 없습니다. 예 : 8 바이트 버퍼에서 이것은 임의의 제약처럼 보이더라도 실패합니다 :'new Uint32Array (buffer, 2, 1)' –

+0

@FrancisAvila : 힌트를 주셔서 감사합니다 .4Byte가 아닌 다중 버퍼가 필요한 경우 그걸 썰어. 위의 코드에서 코드를 수정했지만, 32 비트를 얻기 위해 byteLength에서 * 4 *를 뺄 필요가 있다는 사실을 잊어 버렸습니다. -/ – Bergi

0
var a = Uint8Array(6) 
a.set([1,2,8,0,0,1]) 

i1 = a[a.length-4]; 
i2 = a[a.length-3]; 
i3 = a[a.length-2]; 
i4 = a[a.length-1]; 

console.log(i1<<24 | i2<<16 | i3<<8 | i4); 
1

을 요즘 당신이 IE 11+/Chrome 49+/Firefox 50+ 살 수 있다면, 당신은 DataView을 사용할 수 있습니다 C#에서와 같은 당신의 인생을 거의 쉽게하기 :

var u8array = new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]); // -1 
var view = new DataView(u8array.buffer) 
console.log("result:" + view.getInt32()); 

여기에서 테스트 : https://jsfiddle.net/3udtek18/1/