-
-
Save alediaferia/cfb3a7503039f9278381 to your computer and use it in GitHub Desktop.
/* | |
Copyright (c) 2015-2025 Alessandro Diaferia | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
* Valid options are: | |
* - chunk_read_callback: a function that accepts the read chunk | |
as its only argument. If binary option | |
is set to true, this function will receive | |
an instance of ArrayBuffer, otherwise a String | |
* - error_callback: an optional function that accepts an object of type | |
FileReader.error | |
* - success: an optional function invoked as soon as the whole file has been | |
read successfully | |
* - binary: If true chunks will be read through FileReader.readAsArrayBuffer | |
* otherwise as FileReader.readAsText. Default is false. | |
* - chunk_size: The chunk size to be used, in bytes. Default is 64K. | |
*/ | |
function parseFile(file, options) { | |
var opts = typeof options === 'undefined' ? {} : options; | |
var fileSize = file.size; | |
var chunkSize = typeof opts['chunk_size'] === 'undefined' ? 64 * 1024 : parseInt(opts['chunk_size']); // bytes | |
var binary = typeof opts['binary'] === 'undefined' ? false : opts['binary'] == true; | |
var offset = 0; | |
var self = this; // we need a reference to the current object | |
var readBlock = null; | |
var chunkReadCallback = typeof opts['chunk_read_callback'] === 'function' ? opts['chunk_read_callback'] : function() {}; | |
var chunkErrorCallback = typeof opts['error_callback'] === 'function' ? opts['error_callback'] : function() {}; | |
var success = typeof opts['success'] === 'function' ? opts['success'] : function() {}; | |
var onLoadHandler = function(evt) { | |
if (evt.target.error == null) { | |
offset += evt.target.result.length; | |
chunkReadCallback(evt.target.result); | |
} else { | |
chunkErrorCallback(evt.target.error); | |
return; | |
} | |
if (offset >= fileSize) { | |
success(file); | |
return; | |
} | |
readBlock(offset, chunkSize, file); | |
} | |
readBlock = function(_offset, length, _file) { | |
var r = new FileReader(); | |
var blob = _file.slice(_offset, length + _offset); | |
r.onload = onLoadHandler; | |
if (binary) { | |
r.readAsArrayBuffer(blob); | |
} else { | |
r.readAsText(blob); | |
} | |
} | |
readBlock(offset, chunkSize, file); | |
} |
@bevancollins - readAsBinaryString is non-standard. See https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString:
This method has been removed from the FileAPI standard. FileReader.readAsArrayBuffer() should be used instead.
chunk_read_callback, error_callback, chunk_size: camelCase please. Great solution tho! Didn't realize files could be slice
d
Here's a simpler version btw:
var EventEmitter = require("events").EventEmitter
// file - The file to read from
// options - Possible options:
// type - (Default: "Text") Can be "Text" or "ArrayBuffer" ("DataURL" is unsupported at the moment - dunno how to concatenate dataUrls
// chunkSize - (Default: 64K) The number of bytes to get chunks of
// Returns an EventEmitter that emits the following events:
// data(data) - Returns a chunk of data
// error(error) - Returns an error. If this event happens, reading of the file stops (no end event will happen).
// end() - Indicates that the file is done and there's no more data to read
// derivedfrom here http://stackoverflow.com/questions/14438187/javascript-filereader-parsing-long-file-in-chunks
function read(file, options) {
var emitter = new EventEmitter()
if(options === undefined) options = {}
if(options.type === undefined) options.type = "Text"
if(options.chunkSize === undefined) options.chunkSize = 64000
var offset = 0, method = 'readAs'+options.type//, dataUrlPreambleLength = "data:;base64,".length
var onLoadHandler = function(evt) {
if(evt.target.error !== null) {
emitter.emit('error', evt.target.error)
return;
}
var data = evt.target.result
offset += options.chunkSize
emitter.emit('data', data)
if (offset >= file.size) {
emitter.emit('end')
} else {
readChunk(offset, options.chunkSize, file)
}
}
var readChunk = function(_offset, length, _file) {
var r = new FileReader()
var blob = _file.slice(_offset, length + _offset)
r.onload = onLoadHandler
r[method](blob)
}
readChunk(offset, options.chunkSize, file)
return emitter
}
Hi,
in chrome (at least)
evt.target.result.length for binary chunks return undefined, the line 29 should be:
offset += binary ?evt.target.result.byteLength: evt.target.result.length;
otherwise you will get the first chunk in binary mode, the rest will be empty.
you really save my live ❤️ works like a charm, I use a URL.createObjectURL
to preview the file (.mp4)
What's the best way of determining if the file is binary or text?
I love it! This is a great starting point for my Google Cloud Storage resumable file upload.
@salazarr-js can u please elaborate, how did you do that ?
@alediaferia I would like to use this code in a project and I am wondering what is the license for it. Thanks in advance.
@bernawastaken hey! feel free to use it, I added a MIT license at the top of the file.
Thanks ! @alediaferia
I believe that readAsBinaryString should be used instead of readAsArrayBuffer