브라우저에서 대용량 파일 다루기 - 개념편
브라우저에서 파일 다루기
목적: 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없이 읽기 위한 방법을 작성할 예정
함께보면 정말 좋은 자료