티스토리 뷰

반응형

브라우저에서 파일 다루기

목적: 2gb이상의 파일을 브라우저에서 효율적으로 다루기 위한 방법을 알아보기

해당 포스팅이 다 게재되면 할 수 있는 것
- 수십, 수백메가 또는 기가단위의 파일을 읽으며 어떤 단어가 몇번 포함되는지를 백엔드 통신없이 오로지 클라이언트에서만 수행할 수 있다.
- 대용량파일을 읽는 많은 연산을 하는 동안 브라우저가 Block되지않게 해당 연산을 백그라운드에서 처리할 수 있다.

 

0. 들어가기 전 보면 좋을 개념들

  • 버퍼메모리

 

0.1 버퍼메모리

  • 주기억장치 <- 버퍼메모리 -> 주변장치
  • 위 둘간의 사이에서 정보가 오갈 때 임시로 기억해두고 사용할 수 있는 공간
  • 둘 간의 처리속도가 차이가 날 때 데이터 유실이 있을 수 있으므로 유실을 없애기 위해 데이터를 일시적으로 보관하는 곳

 

1. File

  • File은 Blob의 한 종류다
    • Blob ?

1.1 blob

Blob이 파일의 상위개념이고, 데이터를 텍스트뿐아니라 바이너리 형태로도 보며 데이터처리도 가능한 객체
  • 파일의 불변하는 미가공데이터를 뜻함
  • 텍스트, 바이너리 형태로 읽을 수 있고 ReadableStream으로 변환해 stream method를 통해 데이터 처리가 가능함
  • Blob.arrayBuffer() -> Blob의 전체 데이터를 ArrayBuffer로 만듬
  • Blob.stream() - Blob to ReadbleStream
  • Blob 또는 파일 자체는 사실 데이터 자체라기보다는 데이터를 간접적으로 접근하기 위한 포인터 객체

 

1.2 ReadbleStream

스트림이 포함된 fetch가 등장하기전 까지 리소스를 처리하려면 전체 파일을 다운로드해야 처리할 수 있었지만

Stream 도입 후 버퍼, 문자열 또는 blob 생성할 필요 없이 즉시 JS로 데이터를 처리할 수 있게되었다.

  • 바이트 데이터를 읽을 수 있는 스트림을 제공한다.
  • 데이터를 여러 청크로 나누어서 보내주는 형태의 구현체
  • 대용량의 데이터처리하거나 비동기적으로 데이터를 처리할 때 유용함
  • 수신쪽의 속도를 조절하여 청크를 빨리 생성하는 것을 중지할 수 도 있음
  • TransformStream을 통해 WritableStream 으로도 변환가능
  • 티잉이라고 불리는 작업으로 Stream을 분기할 수 있음- 직접 해봐야 이해가 빠를 것 같아 아직은 잘 모르는 단계
    • Stream은 되감을 수 없기 때문에 분기(두개의 스트림을 생성함)를 통해 Web worker 또는 Brower에 보내어 처리가 가능하다.
    • 여러 WebWorker로 던지고(병렬로 처리) 또 워커끼리 통신이 가능하기에 더 빠른 작업이 진행될 수 있다!!
  • 스트림 데이터는 청크라는 작은 단위로 순차적으로 판독됨

 

파일데이터는 이런 형태로 된다는 것은 알겠고 읽으려면 FirleReader API를 쓰면 된다

 

FileReader API

Web server에 파일을 업로드하지 않아도 유저 파일들에 접근할 수 있도록 하는 HTML5 API
파일 읽는 방법도 여러가지가 있는데 이외의 것들은 MDN에 자세히 기술되어있다.

  • FileReader.readAsText()
    • readAsText()는 처리하기 이전에 full file을 메모리에 넣는다.
    • 따라서 파일 사이즈 큰 파일(수십메가~기가)에 사용할 수 없음.- 브라우저 깨진다.
  • 대용량파일을 read하기 위해선 FileReader.readAsArrayBuffer() 을 사용해야한다.
  • FileReader.readAsArrayBuffer()의 결과는 전체 파일의 ArrayBuffer가 오게되는데, 이를 그대로 읽으면 안되고(byte형태를 decode해야하므로 그 순간에 메모리가 차지됨) slice해서 작은단위로 읽어야한다.

 

결론

- input을 통해 업로드하는 파일은 Blob Obj를 확장시킨 File Object로 Load된다.

- 해당 File Object는 파일의 크기만큼 메모리에 저장되는 것이 아닌 포인터객체형태로 데이터를 가리키기만 한다.

- File의 데이터를 메모리에 저장하지 않고 읽기위해서는 stream방식으로 Chunk만큼씩 받거나 또는 ArrayBuffer형태로 받아서 slice해서 읽을 수 있다.

- 읽는 것과 받는 것은 다르다. 청크만큼 받은 데이터를 읽기 위해선 bufferSize만큼 메모리에 올려야하고 버퍼사이즈가 크다면 브라우저가 깨질 것이므로 적절한 버퍼사이즈만큼씩 읽어야한다.

 

다음 포스팅에선 대용량 파일을 block없이 읽기 위한 방법을 작성할 예정

 

 

함께보면 정말 좋은 자료

https://web.dev/i18n/ko/streams/

https://ui.toast.com/weekly-pick/ko_20160222

 

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
농담곰의 고군분투 개발기