본문 바로가기
개발(Development)/JS(자바스크립트)

자바스크립트 File API 파헤치기: Blob, File, FileReader, FileList, BlobURL

by 카레유 2021. 12. 1.

자바스크립트는 바이너리 데이터를 다루기 위한 방법으로 Buffer와 FileAPI를 제공한다.

 

1. Buffer: 개발자가 메모리 관점에서 바이너리 데이터를 다룰 수 있다.

2. File API: 파일(png, mp3등)이나 입출력장치(마이크, 카메라, 화면 등)의 바이너리 데이터를 다룰 수 있다.

 

▼이 중 Buffer(ArrayBuffer, TypedArray 등)에 대해서는 아래 글에서 아주 상세하게 정리해 두었다.▼

자바스크립트 버퍼(Buffer): ArrayBuffer, TypedArray 파헤치기!

 

이번 글에서는 File API를 정리한다.


# FILE API 란?

FILE API란 단순 텍스트 데이터 뿐만 아니라 이미지, 오디오, 비디오 등의 대용량 바이너리 데이터를 다루기 위한 API이다.

구체적으로 File API는 Blob, File, FileReader, FileList 객체로 구성되어 있다.

 

- Blob: 주로 "파일 형태가 아닌" 바이너리 데이터(마이크 소리, canvas그림 등)를 다룬다.

- File: Blob을 상속 받는 객체로, 주로 "파일 형태"의 바이너리 데이터(mp3, png 파일 등)를 다룬다. 

- FileReader: File이나 Blob에 저장된 바이너리 데이터를 읽어들이는 객체다.

- FileList: HTML Input엘리먼트를 통해 입력 받은 파일(File객체 형태)들을 저장하는 유사배열객체다.

 

하나씩 자세히 살펴보자


#Blob 이란?

Blob이란 특정 "MIME Type"의 "바이너리 데이터"를 저장하는 객체다.

Blob 자체가 Binary Large Object의 약자로, 대용량 바이너리 데이터 객체를 의미한다.

 

Blob은 바이너리 데이터를 다루기 때문에 텍스트 뿐만 아니라 이미지, 오디오, 비디오 데이터도 다룰 수 있다.

실제 사용 시에는 주로 "파일 형태가 아닌 바이너리 데이터"(마이크 소리, 카메라 영상, 화면 등)를 다룬다.

(mp3, png 등의 파일을 다룰 땐 Blob을 상속 받는 File객체를 주로 사용한다)

 

예를 들어 마이크, 카메라 등를 통해 입력 받은 오디오, 비디오 데이터는 Blob객체 형태로 들어온다.

따라서 개발자는 Blob객체를 통해 해당 오디오, 비디오 데이터를 다룰 수 있다.

 

먼저 Blob 객체를 생성하는 방법을 살펴보고,

생성된 Blob객체를 실제로 활용하는 방법을 정리해 보자.


# Blob을 생성하는 방법

Blob객체를 생성하는 방법은 3가지 정도가 있다.

 

1. 생성자 방식

2. 기존 Blob객체의 일부 취득

3. 마이크, 카메라, 화면 등에서 취득

* 화면에서 Blob 데이터를 취득하는게 의아할 수 있는데, canvas를 통해 그리는 그림이나 화면의 일부 영역을 캡처한 데이터라고 보면 된다.

 

1. 생성자

-  new Blob(source배열, {type: "MIME Type", endings: "transparent"}); 

* source 배열: ArrayBuffer, ArrayBufferView, Blob, File, DOMStrring를 요소로하는 배열을 입력 받는다.

* option 객체: MIME Type과 문자열처리 방식을 설정한다.

   ㄴ type: MIME Type을 객체 형태로 입력받는다.("image/png", "audio/*" 등. 디폴트 "")

   ㄴ endings: \n을 포함하는 문자열 처리 방식("transparent" | "native". 디폴트 "transparent")

 

const blob = new Blob(["저는", "카레유", "입니다"], {type: "text/plain"});

console.log(blob); // Blob {size: 24, type: 'text/plain'}

 

Blob 생성자는 입력받은 배열의 요소들을 모두 합쳐 바이너리 데이터 형태로 저장하는 Blob객체를 반환한다.

 

그런데 데이터를 배열 형태로 입력 받는 이유는 무엇일까?

 

일반적으로 바이너리 데이터가 조금씩 쪼개서 chunk단위로 들어오기 때문이다.

또한 대용량의 바이너리 데이터는 chunk단위로 쪼개어 사용할 일이 많다.

 

예를 들어 마이크를 통해 입력 받는 소리(이진 데이터)는 Blob객체 형태로 여러차례 연달아 들어온다.

개발자는 입력받은 여러 개의 Blob객체들을 배열에 담아 새로운 Blob으로 만들어 통합해서 사용하면 된다.

 

const totalBlob = new Blob([blob_1객체, blob_2객체, ...], {type: "audio/ogg codecs=opus"});

 

 

2. slice()메서드

- 메서드:  Blob.prototype.slice(start, end, contentType

* start: 시작 지점(byte 단위)

* end: 종료 지점(byte 단위)

* contentType: 저장할 컨텐츠의 MIME Type

 

// 생성자로 만들어둔 Blob
const blobOrginal = new Blob(["저는", "카레유", "입니다"], {type: "text/plain"});
console.log(blobOrginal); // Blob {size: 24, type: 'text/plain'}

// 0~6byte 까지만 쪼갠 Blob 생성
const blobSliced = blobOrginal.slice(0, 6, "text/plain");
console.log(blobSliced); // Blob {size: 6, type: 'text/plain'}

 

- slice()메서드는 기존 Blob 데이터를 byte단위로 쪼개어 만든 새로운 Blob객체를 반환한다.

- 파라미터 생략시, 동일한 바이너리 데이터를 갖는 Blob을 반환한다.

 

const blobOrginal = new Blob(["저는", "카레유", "입니다"], {type: "text/plain"});
console.log(blobOrginal); // Blob {size: 24, type: 'text/plain'}

const blobCopied = blobOrginal.slice();
console.log(blobCopied); // Blob {size: 24, type: ''}

 

데이터가 너무 큰 경우, 임의의 크기(chunk)로 나누어 사용해야 하는데

이 때 slice()메서드로 Blob을 쪼개어 사용한다.

 

3. 입력 받는 Blob

마이크, 오디오, 화면 등을 통해 입력 받는 데이터는 주로 Blob객체 형태로 들어온다.

이를 위해서는 Media Stream Recording API를 다루어야 하기 때문에 여기서는 일단 소개만 해둔다.


# Blob의 프로퍼티와 메서드

1. 프로퍼티

-  Blob.prototype.size : Blob 바이너리 데이터의 크기(byte단위)

-  Blob.prototype.type : Blob 바이너리 데이터의 MIME 타입

 

2. 메서드: 

-  Blob.prototype.arrayBuffer() : Blob의 데이터를 binary 형태의 Promise<ArrayBuffer> 으로 반환

-  Blob.prototype.text() :  Blob의 데이터를 UTF-8 text 형태의 Promise<String> 으로 반환

-  Blob.prototype.stream() : Blob의 데이터를 ReadableStream으로 변환하여 반환

-  Blob.prototype.slice(start, end, contentType) : byte단위로 쪼갠 Blob객체 반환(위에서 다루었다)

 

// Blob객체 생성
const blob = new Blob(["안녕하세요", "카레유", "입니다"], {type: "text/plain"});

// 텍스트 확인
blob.text().then((value)=>{
    console.log(value); // "안녕하세요카레유입니다"
});


// Blob객체 쪼개기(0~6byte까지)
const blobSliced = blob.slice(0, 6, "text/plain");

// 텍스트 확인
blobSliced.text().then((value)=>{
    console.log(value); // "안녕"
});

 

Blob객체에 저장된 데이터는 브라우저의 HTML상에서 url주소로 접근하도록 구현할 수도 있다.

이를 객체URL이라고 하는데 img, audio, video 엘리먼트의 src에 적용할 수 있다.


# 객체URL이란?(Object URL == Blob URL)

객체URL이란 Blob객체를 가르키는 URL이다. (Blob URL이라고도 한다.)

객체URL은 아래와 같은 형태의 문자열 값으로, Blob객체의 바이너리 데이터를 임시로 참조할 수 있는 주소이다.

blob:http://localhost:80/c74773ce-aaab-47f4-8fba-09cce8ef4abe

 

생성된 객체URL은 <audio>, <video>, <img> 태그 등의 src 값으로 사용할 수 있다.

단, 객체URL은 생성된 페이지 내에서만 유효하며, 다른 페이지로 넘어가면 더이상 사용할 수 없다.

 

1. 객체 URL 생성 방법

- 페이지 내에서 Blob에 담긴 바이너리 데이터를 참조할 수 있는 URL을 생성한다.

 window.URL.createObjectURL(Blob) 

 

2. 객체 URL 해지 방법

- 객체URL을 이미 사용하여 더 이상 필요 없는 경우, 페이지에 머무르고 있는 상태에서도 해지할 수 있다.

 window.URL.revokeObjectURL(Blob) 

 

객체 URL을 생성해 img, audio, video 태그의 src로 설정하면,

Blob객체에 저장된 바이너리 데이터를 MIME Type에 맞게 해석하여 이미지, 오디오, 비디오 등으로 렌더링 한다.

(Blob은 특정 MIME Type 형태의 이진데이터를 저장하고 있는 객체다.)

 

아래에서 사용 방법을 살펴보자.


# Blob 사용 방법

브라우저 환경에서는 바이너리 데이터를 주로 Blob객체를 통해 다룬다.

 

예를 들어 마이크로 입력 받은 소리(바이너리 데이터)는 브라우저에 의해 Blob객체로 감싸져서 들어온다.

따라서 개발자는 마이크로 입력 받은 소리 데이터를 Blob객체를 통해서 다루게 된다.

 

다음은 마이크로 입력받은 소리를 <audio> 태그를 통해 재생하는 방법을 단순화한 것이다.

(마이크를 통해 소리를 Blob으로 받는 과정은Media Stream Recording API 등을 이용해야 하므로 여기선 생략...)

 

1. 마이크를 통해 들어온 여러개의 소리 조각들(Blob)을 하나의 Blob으로 합친다.

const blob = new Blob([오디오Blob1, 오디오Blob2, ... ], {"type": "audio/ogg codecs=opus"});

 

2. 합쳐진 Blob을 "객체URL"(object URL)로 생성한다.

const audioURL = window.URL.createObjectURL(blob);

 

3. 생성된 "객체URL"을 <audio>태그의 src 로 적용한다.

$audioElement.src = audioURL;

 

4. 오디오를 재생한다.

$audioElement.play();

 

또 다른 예로 Blob에 저장된 텍스트 데이터를 다운로드 받는 기능을 구현해보자.

a 엘리먼트의 href, donwoload 속성을 설정하면, 링크 클릭 시 Blob에 저장된 데이터를 지정한 파일명으로 다운로드 받을 수 있다.

 <a href="객체URL" download="파일명.txt"> 

 

// Blob객체 생성
const blob = new Blob(["안녕하세요", "카레유", "입니다"], {type: "text/plain"});

// Blob URL 생성
const objectURL = URL.createObjectURL(blob);

// a 엘리먼트 생성 및 속성 설정
const anchor = document.createElement("a");
anchor.innerText = "다운로드";

// 다운로드를 위해 href 및 download 속성 설정
anchor.href = objectURL; // 위에서 생성한 Blob URL 설정
anchor.download = "hi.txt"; // 다운로드 받을 파일명 설정

// body에 a엘리먼트 추가
document.querySelector("body").append(anchor);

# File 객체란?

File객체란 자바스크립트에서 파일을 다루기 위한 객체로 Blob을 상속 받는다.

이를 위해 파일을 다루는데 필요한 name(파일명), lastModifiedData(최종수정일) 프로퍼티가 추가되어 있다.

따라서 File은 Blob으로 할 수 있는 모든 것을 할 수 있으며, Blob을 요구하는 모든 곳(함수의 인자 등)에 사용될 수 있다.

 

Blob은 주로 파일 형태가 아닌 바이너리 데이터(마이크 목소리, canvas 그림 등)를 다루는 객체이며,

File은 주로 파일 형태의 바이너리 데이터(mp3, png 등)다루는 객체다.


# File 생성 방법

File객체를 생성하는 방법은 주로 2가지가 사용된다.

 

1. 생성자

2. input 엘리먼트 등을 통해 취득

 

1. File() 생성자

new File(source배열, name, {type: "text/plain"});

 

* souce배열: 파일에 저장할 데이터. ArrayBuffer, ArrayBufferView, Blob, DOMString을 요소로 하는 배열을 입력 (UTF-8)
* name: 파일명이나 파일의 경로를 나타내는 USVString.
* option객체: 
   ㄴ type: MIME 유형을 나타내는 DOMString. 디폴트는 ""
   ㄴ lastModified: 최종수정일. 디폴트는 Date.now()

 

 

2. Input 엘리먼트 등을 통해 취득

- 예를들어 브라우저 환경에서 <input type="file"> 엘리먼트 등으로 입력된 파일(mp3, png 등)은 File객체 형태로 취득할 수 있다.

- 아래 FileList항목에서 살펴보자.


# FileList

File 객체 여러개를 담고 있는 유사배열객체(Array-like)이다.

 

예를들어,

input:file 엘리먼트 통해 파일 선택하면 onChange 이벤트가 발생하는데,

onChange 이벤트 핸들러에서 input엘리먼트.files로 FileList 배열객체를 참조할 수 있다.

FileList배열에는 선택된 파일이 순서대로 File객체 형태로 저장되어 있다.

만약 파일 1개만 선택된 경우라면 FileList[0] 에 해당 File객체가 저장되어 있다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

	<!-- input 엘리먼트 -->
    <input type="file" name="input_file" id="input_file">
    
    <!-- audio 엘리먼트 -->
    <audio id="audioElement"></audio>

    <script>
        // 엘리먼트 취득
        const $audioElement = document.getElementById("audioElement");
        const $input_file = document.getElementById("input_file");

        // 파일 입력 이벤트 처리
        $input_file.onchange = function (event) {

            // 1. FileList 취득
            const fileList = $input_file.files;

            // 2. File 취득
            const file = fileList[0];

            // 3. Blob URL 생성
            const blobURL = window.URL.createObjectURL(file);

            // 4. audio 엘리먼트의 src로 설정 및 재생
            $audioElement.src = blobURL;
            $audioElement.play();
        }

    </script>
    
</body>
</html>

# FileReader

File이나 Blob 객체가 저장하고 있는 바이너리 데이터를 비동기로 읽어 주는 객체다.

 

데이터를 읽는 방식에 따라 4가지 메서드가 제공된다.

 

1.  FileReader.prototype.readAsArrayBuffer(File | Blob)

- File이나 Blob의 바이너리 데이터를 읽어서 ArrayBuffer로 반환

 

2.  FileReader.prototype.readAsBinaryString(File | Blob) 

- File이나 Blob의 바이너리 데이터를 읽어서 String으로 반환

 

3.  FileReader.prototype.readAsDataURL(File | Blob) 

- File이나 Blob의 바이너리 데이터를 읽어서 객체 URL로 반환

 

4.  FileReader.prototype.readAsText(File | Blob) 

- File이나 Blob의 바이너리 데이터를 읽어서 텍스트로 반환

 

 

읽기가  완료되면  FileReader객체에 load이벤트가 발생하며, FileReader객체.result 로 결과물을 참조할 수 있다.

 

// 1. Blob 객체 생성(File객체도 사용 가능)
const blob = new Blob(["안녕하세요", "카레유", "입니다"]);

// 2. FileReader 객체 생성
const fileReader = new FileReader();

// 3. FileReader로 Blob 데이터를 텍스트로 읽어들이기
fileReader.readAsText(blob);

// 4. FileReader 읽기 작업 완료 이벤트 처리
fileReader.onload = (event)=>{

	// 5. FileReader가 읽은 내용 확인
    console.log(fileReader.result); // "안녕하세요카레유입니다"
}

# Blob, File관련 레퍼런스 정리

지금까지 자바스크립트의 Blob과 File에 대해 간단하게 정리해보았다.

더 자세한 내용은 아래의 레퍼런스를 참고하며 좋을듯 하다.

 

1. File API: https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications

2. Blob: https://developer.mozilla.org/en-US/docs/Web/API/Blob

3. File: https://developer.mozilla.org/en-US/docs/Web/API/File

4. FileList: https://developer.mozilla.org/en-US/docs/Web/API/FileList

5. FileReader: https://developer.mozilla.org/en-US/docs/Web/API/FileReader

6. ObjectURL: https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL


사실 File API는 이미지, 오디오, 비디오 등의 미디어를 바이너리 데이터로 다루기 위해 많이 사용되는듯 하다.

즉, Media Capture and Streams API, Media Stream Recording API나 Web Audio API 를 사용할 때 많이 접하게 된다.

 

이에 대해서도 차근 차근 정리해볼 계획이다.

 

▼Media Capture and Streams API 에 대한 글▼

자바스크립트 Media Capture and Streams API: MediaStream, MediaStreamTrack

 

 

 

댓글