IterableFile.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. // Based on
  2. // https://gist.github.com/grishgrigoryan/bf6222d16d72cb28620399d27e83eb22
  3. interface IConfig{
  4. chunkSize: number;
  5. }
  6. const DEFAULT_CHUNK_SIZE: number = 64 * 1024; // 64K
  7. export class IterableFile implements AsyncIterable<Buffer> {
  8. private reader: FileReader;
  9. private file: File
  10. private config: IConfig = { chunkSize: DEFAULT_CHUNK_SIZE }
  11. constructor (file: File, config: Partial<IConfig> = {}) {
  12. this.file = file;
  13. this.reader = new FileReader();
  14. Object.assign(this.config, config);
  15. }
  16. [Symbol.asyncIterator] () {
  17. return this.readFile();
  18. }
  19. get chunkSize () {
  20. return this.config.chunkSize;
  21. }
  22. get fileSize () {
  23. return this.file.size;
  24. }
  25. readBlobAsBuffer (blob: Blob): Promise<Buffer> {
  26. return new Promise((resolve, reject) => {
  27. this.reader.onload = (e) => {
  28. e.target?.result && resolve(typeof e.target.result === 'string' ? Buffer.from(e.target.result) : Buffer.from(e.target.result));
  29. e.target?.error && reject(e.target.error);
  30. };
  31. this.reader.readAsArrayBuffer(blob);
  32. });
  33. }
  34. async * readFile () {
  35. let offset = 0;
  36. let blob;
  37. let result;
  38. while (offset < this.fileSize) {
  39. blob = this.file.slice(offset, this.chunkSize + offset);
  40. result = await this.readBlobAsBuffer(blob);
  41. offset += result.length;
  42. yield result;
  43. }
  44. }
  45. }
  46. // Usage:
  47. // let iterableFile = new IterableFile(file)
  48. // for await (const chunk: Buffer of iterableFile) {
  49. // doSomethingWithBuffer(chunk)
  50. // }