티스토리 뷰

Programming language/javascript

Blob 객체

hello-world 2019. 8. 8. 16:42
728x90
반응형

Blob

Blob은 일련의 데이터를 처리하거나 간접 참조하는 객체다.

Blob이란 이름은 SQL 데이터베이스에서 유래하였으며 '대형 이진 객체(Binary Large Object)를 의미한다.

자바스크립트에서 Blob은 흔히 이진 데이터를 나타내며 해당 데이터의 크기가 매우 클 수도 있지만,

두가지 특징 모두 강제된 사항은 아니다.

 

Blob은 대개 바이트의 크기를 알아내거나 해당 MIME 타입이 무엇인지 요청하며,

데이터를 작은 Blob으로 잘게 나누는 등의 작업에 사용된다.

 

"즉, 데이터 자체라기보다는 데이터를 간접적으로 접근하기 위한 객체인 것이다."

 

var blob=....
blob.size   //Blob의 바이트 단위 크기
blob.type   //Blob의 MIME타입을 저장, 알 수 없으면 ""를 저장한다.

//Blob의 첫 1킬로바이트를 텍스트로 가져온다.
var subblob=blob.slice(0, 1024, "text/plain");
//Blob의 마지막 1킬로바이트를 타입 없이 가져온다.
var last=blob.slice(blob.size-1024, 1024)

웹브라우저는 메모리 또는 디스크에 Blob을 저장할 수 있으며, Blob은 비디오 파일과 같이 매우 커서,

메모리에 적재하려면 slice()를 활용하여 작은 조각으로 먼저 분리해야 할 수도 있다.

데이터의 크기가 매우 크기 때문에 디스크를 사용해야 하므로 Blob API 는 비동기 방식으로 동작한다.

 

- Blob은 구조체 복제 알고리즘의 지원을 받는다. 즉 다른 창이나 스레드로부터 message 이벤트를 통해 Blob을 획득 할 수 있다.

 

- 클라이언트 측 데이터베이스로부터 Blob을 가져올 수도 있다.

 

- XHR2 규격의 최신 기능을 활용한 HTTP스크립팅을 통해 웹에서 Blob을 다운로드 할 수 있다.

 

- BlobBuilder 객체를 사용하면 문자열이나 ArrayBuffer 객체 또는 기타 다른 Blob 외에 사용자 Blob을 만들 수도 있다.

 

- 클라이언트 측 자바스크립트의 File객체는 Blob의 하위 자료형(subtype) 이라는 것이다.

파일은 데이터의 'Blob'에서도 얻을 수 있고 drag-and-drop API를 통해 얻을 수 있다.

파일 시스템 API를 통해서도 얻을 수 있다.

 

- createObjectURL() 함수를 사용하면 , 특수 URL blob:// 이 가리키는 Blob의 내용을 가져올 수 있으며,

이 URL은 DOM 이나 CSS를 활용할 수도 있다.

 

- FileReader 객체를 사용하면 Blob의 내용을 비동적으로 문자열이나 ArrayBuffer로 추출할 수 있다.

 

Blob 으로써의 파일

로컬 파일 접근을 허용하는 브라우저에서 <input type="file"> 요소의 files 프로퍼티는 FileList 객체일 것이다.

이 유사 배열 객체는 사용자가 선택한  0개 이상의 File 객체 목록이다.

File객체는 name과 lastModifiedDate 프로퍼티가 존재하는 Blob 객체다.

<script>
 function fileInfo( files ){
     //files 는 유사 배열 객체이다.
     for(var i=0;i<files.length;i++){
          var f=files[i];
          //f.name - 경로를 제외한 파일명
          //f.size, f.type은 Blob 프로퍼티다.
          //f.lastModifiedDate는 File 프로퍼티다.
          console.log( f.name, f.size, f.type, f.lastModifiedDate );
     }
 }
</script>
<!-- 여러개의 이미지 파일을 선택할 수 있고, 선택목록을 fileInfo()로 전달 -->
<inuput type="file" accept="image/*" multiple onchange="fileInfo(this.files)"/>

애플리케이션이 drop이벤트를 전달받으면 해당 이벤트 객체의 dataTransfer.files 프로퍼티에는

해당 파일의 내역이 FileList로 존재하게 된다. 

Blob 읽어 들이기

- Blob은 Blob URL을 통해 해당 내용을 간접적으로 접근할 수 있는 불투명한 데이터 덩어리이다.

FileReader 객체는 Blob에 포함된 문자난 바이트들을 읽을 수 있게 하며 BlobBuilder와는 반대의 성격을 가진 것이라고 생각할 수 있다.

Blob은 매우 큰 크기의 객체를 파일 시스템에 저장할 수 있으므로 Blob의 내용을 읽기 위한 FileReader 객체 API는 XMLHttpRequest API와 매우 비슷하게도 비동기적이다.

 

FileReader 사용

1. new FileReader() 인스턴스 생성

2. 이벤트 핸들러 정의 ( load, error, progress 등 )

3. readAsText(), readAsArrayBuffer(), readAsDataURL(), readAsBinaryString() 메서드 중 하나로 전달.

 

 

 

ex) FileReader를 활요한 텍스트 파일 읽기.

 

javascript 부분

function readfile(f){
  var reader=new FileReader();
  reader.readAsText(f);
  reader.onload=function(){
     var text=reader.result; //파일의 내용.
     var out=document.getElementById("output");
     out.innerHTML="";
     out.appendChild( document.createTextNode(text) );
  }
  reader.onerror=function(e){
     console.log("Error", e);
  }
}

- FileReader는 지정된 Blob을 읽으면서 readState 프로퍼티를 업데이트 한다.

- readState 값은 아무것도 읽지 않았다면 0 , 어떤 데이터를 읽으면 1, 모두 다 읽어 들여서 작업을 완료하면 2

- result 프로퍼티에는 부분적이거나 완전한 결과가 문자열 또는 ArrayBuffer로 담겨 있다.

- 일반적으로 state와 result 프로퍼티를 주기적으로 확인하는 대신 onprogress 또는 onload 이벤트 핸들러를 사용한다.

 

html

<input type="file" onchange="readfile(this.files[0])" />
<pre id="output"></pre>

 

ex)  파일의 첫 4바이트 읽어 들이기

 

javascript

function typefile(file){
  var slice=file.slice(0,4) //파일의 시작부분만을 잘라낸다.
  var reader=new FileReader();
  reader.readAsArrayBuffer(slice)
  
  reader.onload=function(e){
    var buffer=reader.result;
    var view=new DataView(buffer);      //결과 바이트의 접근 권한을 획득. DataView객체는 하단 참고.
    var magic=view.getUnit32(0, false);   //빅 엔디언으로 4바이트를 읽어 들인다.
    switch( magic){
    	case 0x89504E47 : file.verified_type="image/png"; break;
        case 0x47494638 : file.verified_type="image/gif"; break;
        case 0x25504446 : file.verified_type="application/pdf"; break;
        case 0x504b0304 : file.verified_type="application/zip"; break;
    }
    console.log( file.name, file.verified_type );
  }
}

- readAsArratBuffer() 메서드는 readAsText()와 비슷하지만 파일 내용을 문자열 형태보다는  ArrayBuffer형대로 다룰 때 좀더 적합하다.

- DataView는 ArrayBuffer(혹은 array buffer의 한 영역)를 감싼 ArrayBufferView 객체다.

 

html

<input type="file" onchange=type(this.files[0])" />

 

DataView 객체

- DataView는 ArrayBuffer(혹은 array buffer의 한 영역)를 감싼 ArrayBufferView 객체다.

이 객체에는 1, 2 혹은 4바이트의 부호가 있는 정수와 부호가 없는 정수를 읽고 쓰는 메서드와 4,8바이트의 부동소수점 수를 읽고 쓰는 

메서드가 정의되어 있다. 메서드는 빅엔디안리틀 엔디안 바이트 정렬을 모두 지원한다.

 

비트,바이트, 빅엔디안, 리틀앤디안 등 이해하기 위해서 아래 글을 한번 읽어보자.

(정리하다 먼소리인지 몰라서 찾아봄....나처럼 사전지식이 없다면 꼬옥 읽어보고 혹은 찾아보고 해야 멘붕이 안온닷!!)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

"컴퓨터는 모든 데이터를 2진수로 표현, 처리"

 

Bit(비트)=데이터의 최소 단위 / 2진수의 값(0과 1)을 단 하나만 저장

Byte(바이트)=Bit(비트) 8개가 모여서 구성. 한 문자를 표현할 수 있는 최소 단위.

 

컴퓨터는 데이터를 메모리에 저장할 때 byte(바이트) 단위로 나눠서 저장.

하지만 컴퓨터가 저장하는 데이터는 대게 32bit(4byte)나 64bit(8byte)로 구성.

따라서 이렇게 연속되는 바이트를 순서대로 저장해야 하는데, 이것을 바이트 저장 순서(byte order)라고 한다.

 

이때 바이트가 저장되는 순서에 따라 다음과 같이 두 가지 방식이 있다.

 

1. 빅 엔디안(big endian)

   - 낮은 주소에 데이터의 높은 바이트(MSB, Most Significant Bit)부터 저장하는 방식.

      ex) 정수 0x00000001 이 메모리상에 00 00 00 01 으로 배치

 

2. 리틀 엔디안(little endian)

   -낮은 주소에 데이터의 낮은 바이트(LSB, Least Significant Bit)부터 저장하는 방식.

     ex) 정수 0x00000001 이 메모리상에 01 00 00 00 으로 배치

    var little_endian= new Int8Array( new Int32Array( [1] ).buffer )[0] ===1;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 

"오늘날 대다수 cpu 아키텍처들은 리틀 엔디언 방식을 따른다.

그러나 많은 네트워크 프로토콜과 몇 가지 이진 파일 형식에서는

빅 엔디언 방식의 바이트 순서를 따른다."

 

이때 취득한 데이터의 바이트 순서가 플랫폼의 엔디어 방식과 일치한다고 가정하기 어렵다.

일반적으로 외부 데이터를 활용할 때는 데이터의 각 바이트를 배열로 다루기 위해 Int8Array와 Uint8Array를 사용할 수 있지만

다른 타입 배열을 사용해서 다중바이트의 데이터를 다루어서는 안 된다.

그 대신, 바이트 배열 방식을 명시적으로 지정하여 ArrayBuffer의 값을 읽고 쓰는 메서드를 정의 하고 있는

DataView클래스를 사용하면 된다. ( 말이 어렵다 ㅠㅠ )

var data;   //네트워크로부터 받은 ArrayBuffer라고 가정.
var view=DataView(data); //이 데이터의 뷰를 생성
var int=view.getInt32(0); //0번째 바이트로부터 부호가 있는 32비트 빅엔디언 정수를 가져온다.

int=view.getInt32(4, false);//다음 32비트 정수도 빅엔디언으로 가져온다.
int=view.getInt32(8, true);//다음 4바이트는 리틀 엔디언으로 가져온다.
view.setInt32(8, int, false ); //이 데이터를 다시 빅엔디언 형식으로 기록한다.

- DataView는 8가지의 타입 배열 형식을 위한 각각의 get메서드를 정의한다.

getInt16(), getUint32(), getFloat64()같은 형태다.

1번째 인자 - ArrayBuffer의 몇번째 값으로부터 시작할 지를 지정하는 바이트오프셋이다.

getInt8()과 getUint8()을 제외한 모든 getter 메서드들은 선택적으로 2번째 인자를 boolean값으로 받아들인다.

2번째 인자가 생략되거나 false이면 높은 번지의 바이트를 먼저 배열하는 빅엔디언 형식으로 값을 처리한다.

그리고 true이면 낮은 번지의 바이트를 먼저 배열하는 리틀엔디언 형식으로 값을 처리한다.

 

 

 

참고 : 자바스크립트 완벽가이드 ( javascript the definitive guide 6/e )

728x90
반응형
댓글