FileUtils.js 2.9 KB

12345678910111213141516171819202122232425262728293031
  1. export class ChunkedReader{fileSize(){}
  2. loadedSize(){}
  3. fileName(){}
  4. cancel(){}
  5. error(){}}
  6. export class ChunkedFileReader{constructor(blob,chunkSize,chunkTransferredCallback){this._file=blob;this._fileSize=blob.size;this._loadedSize=0;this._chunkSize=chunkSize;this._chunkTransferredCallback=chunkTransferredCallback;this._decoder=new TextDecoder();this._isCanceled=false;this._error=null;}
  7. read(output){if(this._chunkTransferredCallback){this._chunkTransferredCallback(this);}
  8. this._output=output;this._reader=new FileReader();this._reader.onload=this._onChunkLoaded.bind(this);this._reader.onerror=this._onError.bind(this);this._loadChunk();return new Promise(resolve=>this._transferFinished=resolve);}
  9. cancel(){this._isCanceled=true;}
  10. loadedSize(){return this._loadedSize;}
  11. fileSize(){return this._fileSize;}
  12. fileName(){return this._file.name;}
  13. error(){return this._error;}
  14. _onChunkLoaded(event){if(this._isCanceled){return;}
  15. if(event.target.readyState!==FileReader.DONE){return;}
  16. const buffer=this._reader.result;this._loadedSize+=buffer.byteLength;const endOfFile=this._loadedSize===this._fileSize;const decodedString=this._decoder.decode(buffer,{stream:!endOfFile});this._output.write(decodedString);if(this._isCanceled){return;}
  17. if(this._chunkTransferredCallback){this._chunkTransferredCallback(this);}
  18. if(endOfFile){this._file=null;this._reader=null;this._output.close();this._transferFinished(!this._error);return;}
  19. this._loadChunk();}
  20. _loadChunk(){const chunkStart=this._loadedSize;const chunkEnd=Math.min(this._fileSize,chunkStart+this._chunkSize);const nextPart=this._file.slice(chunkStart,chunkEnd);this._reader.readAsArrayBuffer(nextPart);}
  21. _onError(event){this._error=event.target.error;this._transferFinished(false);}}
  22. export class FileOutputStream{async open(fileName){this._closed=false;this._writeCallbacks=[];this._fileName=fileName;const saveResponse=await Workspace.fileManager.save(this._fileName,'',true);if(saveResponse){Workspace.fileManager.addEventListener(Workspace.FileManager.Events.AppendedToURL,this._onAppendDone,this);}
  23. return!!saveResponse;}
  24. write(data){return new Promise(resolve=>{this._writeCallbacks.push(resolve);Workspace.fileManager.append(this._fileName,data);});}
  25. async close(){this._closed=true;if(this._writeCallbacks.length){return;}
  26. Workspace.fileManager.removeEventListener(Workspace.FileManager.Events.AppendedToURL,this._onAppendDone,this);Workspace.fileManager.close(this._fileName);}
  27. _onAppendDone(event){if(event.data!==this._fileName){return;}
  28. this._writeCallbacks.shift()();if(this._writeCallbacks.length){return;}
  29. if(!this._closed){return;}
  30. Workspace.fileManager.removeEventListener(Workspace.FileManager.Events.AppendedToURL,this._onAppendDone,this);Workspace.fileManager.close(this._fileName);}}
  31. self.Bindings=self.Bindings||{};Bindings=Bindings||{};Bindings.ChunkedReader=ChunkedReader;Bindings.ChunkedFileReader=ChunkedFileReader;Bindings.FileOutputStream=FileOutputStream;