问题
I want to use a FileReader in my web application to partially load a CSV file into the browser. However, I am not able to access partial results in Firefox 27.
My application requires only the first 100k bytes of the CSV file to populate a data preview. Therefore, I setup, start, and then abort the reader after a certain amount of data has been loaded.
Here is an example that works fine in Chrome 35:
warn = (a...) -> console.warn a...
readFile = (file,cb,limit=1e5) ->
warn "start reading file..."
fr = new FileReader
result = null
done = -> cb null,result[..limit]
copy = (e) ->
if e.target.result? then result = e.target.result; warn "copied #{result.length} bytes"
else warn "result is empty"
fr.onloadstart = (e) -> warn "Reading #{file.name} locally..."
fr.onloadend = (e) -> warn "Reading finished (end)"; copy(e); done()
fr.onabort = (e) -> warn "Reading finished (abort)"; copy(e)
fr.onload = (e) -> warn "Reading finished (load)"; copy(e)
fr.onprogress = (e) ->
warn "progress.."; copy(e)
if e.loaded > limit
warn "Read #{e.loaded} bytes of CSV file for data preview. Aborting FileReader."
fr.abort(); fr.onprogress = null
fr.readAsText file
However, the code does not work in Firefox; all copied results are empty when aborting the reader. None of the events e
carries an e.target.result
other than null
, even if the progress
event indicates that some data has been read, as e.loaded
is set correctly and thus the abort()
is also triggered as expected.
Obviously Chrome and Firefox seem to implement the File API differently, i.e., handle the abort()
differently. In Firefox you always have to fully load a file to get any result. For me this is not suitable, since my CSV files have 200MB or more bytes of data, leaving me with a frozen browser when having to load the data completely.
PS: I only care for Chrome and FF. IE and mobile are out of scope for this project
EDIT: Here is the final solution that works nicely in Chrome and Firefox:
readFile = (file,cb,limit=1e4) ->
warn "start reading file..."
fr = new FileReader
done = (e) ->
warn "Read #{e.loaded} of #{file.size} bytes of CSV file for data preview"
cb null,fr.result
fr.onloadstart = (e) -> warn "Reading #{file.name} locally..."
fr.onload = (e) -> warn "Reading finished (load)"; done(e)
fr.readAsText file.slice 0,limit
回答1:
Chrome violates the current spec draft which states for abort()
:
If readyState = LOADING set readyState to DONE and result to null. (source, emphasis mine)
Now, you can argue whether this is a good or bad thing to do...
The best way to read only part of the file is to .slice() the File/Blob object before passing it to the reader, telling the browser to read only part of the file in the first place:
fr.readAsText(file.slice(0, limit));
Of course, you might have to deal with issues when processing multi-byte encodings such as UTF-8... But you'd have to deal with that anyway, even with your Chrome-only abort()
stuff.
来源:https://stackoverflow.com/questions/24809960/accessing-partial-results-of-a-filereader-in-firefox