Base64, Blob, ArrayBuffer, File 개념 알아보기

·2024년 3월 12일
0

Javascript

목록 보기
16/16
post-thumbnail

"Base64, Blob, ArrayBuffer, File 개념 알아보기" 라고 쓰고 "Blog 만들기 플젝의 괴로움"이라고 읽는다...
단순한 CRUD는 이제 Next.js14, prisma 멱살을 잡고 어떻게든 구현은 가능해서 서버와 클라이언트 단에 붙여 놓았다
내 발목을 잡는건 바로 이미지 업로드... 썸네일 등록과 Editor에서 이미지 등록을 해야 하는데, 우선 블로그 작성과 함께 썸네일 등록을 어떻게 처리해야 할지 생각하다가 base64 형태 그대로 DB에 꽂아보자 란 생각을 했다.
플젝 규모가 크지 않아 파일 서버를 굳이 따로 두고 싶지 않았다. 근데 이미지 하나를 넣자마자 Detail API가 미친듯이 느려졌다. 내가 넣은 이미지 화질이 좋은거(185KB)긴 하지만... 이정도까지 느려진다고?
어떤 방식을 써야할까 고민하다가, 파일 형식에 대한 개념이 부족한 나를 발견하고 파일 형식에 대해 먼저 공부해보려고 한다

원시 데이터

웹 개발을 하다보면 이진 데이터를 다루어야 할 때를 마주치곤 한다.
브라우저에선 주로 파일 생성, 업로드, 다운로드 또는 이미지 처리와 관련이 깊고, 서버 사이드인 node.js에선 파일부터 버퍼까지 원시 데이터를 다루는 상황이 있을 수 있다.

정수, 실수, 문자가 아닌 파일, 이미지, 비디오 같은 멀티미디어 같은 데이터는 어떻게 다뤄야 할까?

binary, base64, blob, arraybuffer, buffer, file 타입에 대해서 개념을 알아보고 자바스크립트에서 지원하는 내장 객체를 이용해 이미지 멀티미디어 파일을 어떤 문법으로 변환하고 이용할 수 있는지 살펴보자!

Binary

컴퓨터는 우리가 사용하는 모든 데이터를 0과 1로 저장한다.
Binary란 이진 데이터를 의미하며, 0과 1만을 사용하여 2개의 수를 나타내는 진법을 뜻하는, 컴퓨터를 다루는데 있어 가장 근본이 되는 체계라고 볼 수 있다.

Base64

컴퓨터는 모든 데이터를 0과 1로 저장한다. 그럼 컴퓨터 안에 저장된 데이터를 꺼내 쓰고 싶을 때 어떻게 해야 할까?
우리가 프로그래밍에서 배우는 변수 개념이 바로 이 개념이다. 메모리에 저장된 0과 1로 이루어진 데이터를 변수에 적재해놓고, 필요하면 우리는 변수를 불러 덧셈, 뺄셈을 하는 것으로 컴퓨터 안의 이진 데이터(바이너리)를 다루고 있었던 것이다.

숫자나 스트링이 아닌 이미지나 비디오 같은 복잡한 멀티미디어 파일들은 어덯게 변수 메모리에 저장할까?
변수에 이미지 url을 저장하는건 링크라는 징검다리를 저장할 뿐 이미지 데이터 그 자체를 저장하는 것이 아니다.
이때 등장하는 것이 Base64라는 개념이다. Base64는 0과 1로 이루어진 이진 데이터(바이너리)를 인코딩하여 텍스트 형식으로 변환하는 것을 말한다.

Base64 인코딩 과정

html에 img의 src에 삽입된 이미지 url이 아닌 숫자와 문자로 구성된 긴 코드(data:image/png;base64)가 base64이다.
0과 1로 이루어진 이미지 데이터 자체를 base64 텍스트 기반 포맷으로 변환해줌으로써 우리가 직접 이미지 데이터를 다룰 수 있는 것이다.

만일 우리가 소스 코드 단에 이미지를 불러와 다루어야 한다고 하자.
보통이라면 링크를 통해 불러오거나 로컬 폴더에 저장되어 있는 이미지 파일을 코드에서 제공하는 파일 시스템을 통해 상대경로로 불러와 다뤄본 경험이 있을 것이다. 하지만 파일도 결국 url과 같이 OS에 저장된 징검다리를 불러온 것과 다름이 없다.
그러나 base64로 변환해주면 우리가 직접 소스 코드 단에 이미지 데이터 자체를 저장할 수 있게 된다. 우리가 변수에 문자열이나 숫자를 저장하는 것처럼 변수에 이미지를 저장할 수 있는 것이다.
base64는 이미지 데이터 값을 변환하는 것이 아닌 그냥 출력 형식을 변환하는 것이기 때문에 이미지 자체가 바뀌는 것이 아니라 가능한 것이다. 즉, 이미지 데이터 정보는 이미 base64 텍스트 자체에 포함되어 있기 때문에 결과적으로 링크 url을 통해 서버에 요청하지 않고도 직접 이미지를 사용할 수 있게 된다.

html에서 직접 base64 포맷을 다루는 경우

  • 크키가 작은 이미지를 url이나 파일을 불러오는 것 없이 html에 직접 삽입하는 경우
  • 간단한 페이지를 작성해 임시로 이미지를 사용하는 경우
  • 이미지가 들어간 메일 내용을 html로 작성해서 보내는 경우

특징

바이너리 데이터를 텍스트로 바꾸는 64진법 인코딩을 통해 바이너리 데이터 대비 33% 데이터의 양 증가라는 단점이 있다. 하지만 데이터의 길이가 증가함에도 Base64를 사용하는 가장 큰 이유는 Binary 데이터를 텍스트 기반 규격으로 다룰 수 있기 때문이다.

또한 순수 Binary 형식으로 남아있는 데이터보다 전송, 저장이 훨씬 쉽다. (이진 데이터는 손상될 확률이 높다.)
인코딩할 시, 문자 포맷을 A-Z, a-z, 0-9, /+만 사용하기 때문에 문자 포맷이 달라 데이터를 손상시킬 수 있는 시스템 간에도 안정적으로 전송될 수 있다.

Blob (Binary Large Object)

BLOB은 Binary Large Object의 약자로, ㅈ로 이미지, 오디오, 비디오와 같은 멀티미디어 파일 바이너리를 객체 형태로 저장한 것을 의미한다. 멀티미디어 파일들은 대다수 용량이 큰 경우가 많기 때문에 이를 데이터베이스에 효과적으로 저장하기 위해 고안된 자료형이라고 볼 수 있다.

예를 들어 데이터베이스에 이미지 파일을 그대로 데이터로 저장하고 싶을 때 blob 포맷으로 변환한 뒤 저장할 수 있다. 브라우저 환경에서도 자바스크립트를 이용해 이러한 blob 데이터에 접근하고 사용할 수 있다. 주로 자바스크립트에서 텍스트, 이미지, 사운드, 비디오와 같은 멀티미디어 데이터를 다룰 때 사용한다.

base64와의 차이점

base64는 바이너리 데이터를 다루기 위해 텍스트 형태로 저장한 포맷이다. 반면에 blob은 바이너리 데이터를 다루기 위해 객체로 저장하는 것이다.

base64 포맷으로 이미지 바이너리 파일을 브라우저에 표현하려면 FileReader 객체를 이용해 변환 후 <img> 태그의 src 속성에 넣으면 가능했다. 하지만 문자열이 굉장히 길어져 가독성이 안좋을 뿐 아니라 base64 이미지를 이곳저곳 여러 개 사용할 경우 결과적으로 용량 문제 때문에 문서 자체를 로딩하는데 많은 시간이 걸려 오히려 느려질 수 있다는 단점이 있다.

하지만 blob 데이터는 적절하게 object url로 변환만 해주면 심플하게 브라우저에서 사용할 수 있다. 또한 blob은 객체이기 때문에 다양한 코드 활용성을 지니고 있어 base64로 변환할 수도 있고 buffer로도 변환할 수도 있다.

blob 이미지 다루기

const data = await fetch('https://play-lh.googleusercontent.com/hYdIazwJBlPhmN74Yz3m_jU9nA6t02U7ZARfKunt6dauUAB6O3nLHp0v5ypisNt9OJk');
const blob = await data.blob(); // 이미지 blob 객체 얻기

이렇게 만들어진 blob 객체는 곧바로 사용할 수는 없고, <a>, <img> 태그의 src 속성에 사용할 수 있는 url 타입으로 따로 변환해야 한다.

fetch('https://www.business2community.com/wp-content/uploads/2014/04/Free.jpg')
      .then((response) => response.blob())
      .then((blob) => {
        const url = URL.createObjectURL(blob);
        document.querySelector('img').src = url;
        document.querySelector('a').href = url;
      });

URL.createObjectURL 메서드를 이용하면 blob 객체를 가지고 고유한 url을 생성할 수 있다.
이때 생성되는 url의 형태는 blob:/의 형태를 띄게 된다. 그리고 변환된 url은 src 속성을 가지는 모든 HTML 태그와 CSS 속성에서 사용 가능하다.

blob 객체는 별도로 type(image/png)을 명시하기 때문에 blob 객체를 다운로드, 업로드하는 과정에서 네트워크 요청에서의 Content-Type은 자연스레 명시된 type으로 매칭된다.

특징

변환된 url은 현재 탭의 브라우저 메모리에 저장되고, 저장된 url은 매핑된 blob 객체를 참고하고 있는 형태이다. 이러한 원리 때문에 base64와 달리 짧은 문자열만으로도 원래의 blob 객체에 접근이 가능하고 그에 따른 이미지 등의 파일을 가져올 수 있는 것이다.
따라서 변환된 url은 현재 브라우저 메모리에 적재된 상태이므로 항상 현재 문서에서만 유효하다. 현재 문서를 새로고침하거나 다른 페이지에서 변환된 url을 사용하려 할 경우 제대로 사용할 수 없다.

blob 역시 메모리 이슈가 존재한다.
blob 객체가 url로 변환되어 매핑이 이루어진 채 메모리에 저장되면 명시적으로 해당 url이 해제되기 전까지 브라우저는 해당 url이 유효하다고 판단하기 때문에 자바스크립트 엔진에서 가비지 컬렉션이 이루어지지 않는다.
따라서 blob url을 사용한 후 더이상 사용하지 않을 시점이라고 판단되면 명시적으로 해제해주는 것이 좋다.

cosnt objectURL = window.URL.createObjectURL(blob);
window.URL.revokeObjectURL(objectURL);

변환은 URL.createObjectURL 메서드를 통해 진행했고, 해제의 경우 URL.revokeObjectURL 메서드를 사용한다.

ArrayBuffer

ArrayBuffer 객체는 이미지, 동영상과 같은 멀티미디어 데이터 덩어리를 표준 자바스크립트(브라우저)에서 다루기 위해 도입됐다.

일반적으로 실시간 방송과 같이 영상 내용을 송출할 때에는 영상이라고 하는 실시간 데이터를 계속해서 전달해줘야 유저들이 볼 수 있다. 즉, 어떤 식으로든 커다란 데이터를 잘개 쪼개서 전송해야 하는 상황이 발생한다.
여기서 버퍼(buffer)라는 개념이 등장하는데, 일정 구획만큼의 데이터를 쪼개서 전달하는 stream을 저장한 후 일정 크기가 도달하면 출력 장치나 동영상 플레이어로 전달해주는 중개자 역할을 하는 객체라고 보면 된다. (버퍼링이 바로 이 개념!)

따라서 자바스크립트 용도가 다양해지면서 이처럼 오디오나 비디오 같은 binary data들 역시 다룰 필요성이 생기게 되자, 필요한 메모리 공간을 적절하게 할당해서 사용할 수 있는 유연성이 필요해 ArrayBuffer를 만들게 되었다고 이해하면 된다.

ArrayBuffer는 자바스크립트에서 원시 데이터를 직접 다루는 수단으로 사용되며, 이는 메모리를 개발자가 수동으로 관리할 수 있게 해준다.
지금까지 배운 base64와 blob은 사람이 읽고 다루기 편하게 가공된 데이터 타입이라면, ArrayBuffer는 보다 오리지널에 가깝다고 보면 된다. 레퍼런스 타입으로 되어 있으며, 고정된 길이의 연속된 메모리 공간을 할당해 사용하겠다고 알려주는 역할을 한다.
(오디오 전용인 AudioBuffer, 미디어 전용인 SourceBuffer도 있다.)
특히 성능에 민감한 이슈를 다룬다거나 blob 등의 큰 용량의 파일 데이터를 다루는 경우 ArrayBuffer를 사용해 유연하고 효율적으로 작업할 수 있다.

Buffer

데이터 덩어리를 다루기 위해 Node.js는 진작부터 Buffer 타입을 도이했다.
버퍼는 고정된 크기의 데이터 덩어리를 표현하기 위한 타입이며 Node.js의 많은 API들이 Buffer 타입을 지원한다.
fs 모듈로 로컬 파일을 가져오는 것도 사실 버퍼로 가져오는 것이다.
클라이언트 단에서 ArrayBuffer로 이진 데이터를 다루었다면, 서버 단에서는 Buffer 객체로 이진 데이터를 다룬다고 이해하면 된다.

File, FileReader

File

파일은 우리에게 매우 익숙한 타입이지만, 자바스크립트에서의 File 객체는 Blob 객체를 확장한 객체로 주로 파일시스템과 관련된 기능을 담당한다.
파일시스템은 OS/서버 단의 영역인데, 브라우저 상에서도 파일을 주고 받는 등의 기능이 필요하기 때문에 이를 지원하기 위한 규격으로 볼 수 있다.

브라우저에서 자바스크립트를 이용해 파일을 다루기 위한 방법으로는 File 객체를 이용하거나 input 태그를 이용하는 두 가지가 있다.

new File(fileParts, fileName, [options]);
/*
	- fileParts : Blob / BufferSource / String 과 같은 배열
	- fileName : 파일 이름 (문자열)
	- options : 옵셔널 값
*/
<input type="file" onChange="showFile(this)" />

<script>
  function showFile(input) {
  	// input type='file' 의 경우 추가적으로 multiple 옵션을 지정할 수 있는데 이 경우에는 다량의 File이 배열 형태로 전달되게 된다. 
    // 이때를 고려하여 단일 파일만 전달되는 경우에도 File은 항상 유사 배열로 전달되기 때문에 하나의 파일만 다루는 경우에도 인덱스로 접근하는 것에 주의하자
    let file = input.files[0];
    
    alert(`File name: ${file.name}`); // 파일 이름
    alert(`Last modified: ${file.lastModified}`); // 마지막 수정이 일어난 때의 timestamp
  }
</script>

FileReader

FileReader는 Blob 또는 File과 같은 객체로부터 데이터를 읽어 들이기 위한 목적으로 사용되는 객체이다.
읽어들인 데이터는 주로 이벤트를 사용하여 필요한 타이밍에 데이터를 전달한다.

const reader = new FileReader();

reader.readAsArrayBuffer(blob) // ArrauBuffer 형태로 데이터를 읽어 변환

reader.readAsText(blob, [encoding]) // encoding 방식에 맞게 텍스트 형태로 데이터를 읽어 변환 (기본 인코딩 방식 - utf-8)

reader.readAsDataURL(blob) // base64 형태의 data url로 데이터를 읽어 변환

< 출처 : https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-Base64-Blob-ArrayBuffer-File-%EB%8B%A4%EB%A3%A8%EA%B8%B0-%EC%A0%95%EB%A7%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%89%BD%EA%B2%8C-%EC%84%A4%EB%AA%85 >

profile
개발을 개발새발 열심히➰🐶

0개의 댓글