HTML5 FileAPI FileReader
for React Native, thus FileReader.readAsArrayBuffer
can work as well which is not implemented in react-native/Libraries/Blob/FileReader.js
.
See https://developer.mozilla.org/en-US/docs/Web/API/FileReader
npm install react-native-filereader
For RN >= 0.65, run npm install react-native-blob-util
.
For RN < 0.65, run npm install react-native-blob-util@0.16.3
, and patch manually to fix: with react-native-web product build will export 'URIUtil' (reexported as 'URIUtil') was not found.
You need request permission first in your APP, e.g. ('react-native').PermissionsAndroid
on Android ref to automatically request permission on Android when import file, or android.permission.READ_EXTERNAL_STORAGE
with react-native-permissions.
Since there is global react-native/Libraries/Blob/FileReader.js
and metro babel use it, it's difficult to let
react-native-filereader as a polyfill like window.FileReader = require('./FileReader')
in index.js
.
So you need to port web JS code by replace new FileReader()
to new (require('react-native-filereader'))()
.
Or if you don't want modify the web JS code to port, you can let babel do the job when babel is working, with these 3 steps:
npm install babel-plugin-transform-globals --save-dev
then add overrides
into YOUR_APP/babel.config.js
:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
overrides: [
{
test: 'node_modules/pixelshapern/src/libs/GifLoader.js', // change to your web JS code file path
// test: '**/GifLoader.js', // also can use this [glob](https://www.npmjs.com/package/glob) patterns
plugins: [
[
'transform-globals',
{
import: {
'react-native-filereader': {
FileReader: 'default',
},
},
},
],
],
},
],
};
then npm run rn-fresh
:
watchman watch-del-all; rm -rf /tmp/react-*; rm -rf /tmp/npm-*; rm -rf /tmp/haste-*; rm -rf /tmp/metro-*; node node_modules/react-native/local-cli/cli.js start --reset-cache
PS: overrides
comes from Use babel-plugin into specific file via .babelrc? and be implemented in Allow configs to have an 'overrides' array.
import FileReader from 'react-native-filereader';
var fileReader = new FileReader();
// non-standard alias of `addEventListener` listening to non-standard `data` event
fileReader.on('data', function (data) {
console.log("chunkSize:", data.length);
});
// `onload` as listener
fileReader.addEventListener('load', function (ev) {
console.log("dataUrlSize:", ev.target.result.length);
});
// `onloadend` as property
fileReader.onloadend = function () {
console.log("Success");
};
fileReader.setNodeChunkedEncoding(true || false); // non-standard method
fileReader.readAsDataURL('/storage/emulated/0/Android/data/com.YOUR.APP/files/my-file.txt');
// or
fileReader.readAsArrayBuffer('content://com.android.providers.media.documents/document/image%3A33763');
// or
// fileReader.readAsArrayBuffer({url: 'content://com.android.providers.media.documents/document/image%3A33763'});
// fileReader.readAsArrayBuffer({uri: 'content://com.android.providers.media.documents/document/image%3A33763'});
// fileReader.readAsArrayBuffer({path: '/storage/emulated/0/Pictures/gifs/ani (7).gif'});
PS: content://
can be changed to /storage/
on Android by fs.stat()
in react-native-blob-util.
On Android, sometimes you select a file from /sdcard
by e.g. react-native-system-file-browser, the decodeURIComponent(path)
is content://com.android.externalstorage.documents/document/primary:SOME_DIR/SOME.FILE
and will be fs.stat()
to /storage/emulated/0/Android/data/com.YOUR.APP/files/SOME_DIR/SOME.FILE
in react-native-filereader
thus cause failed to stat path ".../SOME.FILE" because it does not exist or it is not a folder
, in this situation, you should do path = decodeURIComponent(path).replace(/^content:\/\/com.android.externalstorage.documents\/document\/primary:/, '/sdcard/')
in your APP.
<File>
below is one of StringUriPath
, {path: string}
, {url: string}
, {uri: string}
, {buffer: Buffer}
, {stream: ReadStream}
.readAsArrayBuffer(<File>)
.readAsBinaryString(<File>)
.readAsDataURL(<File>)
.readAsText(<File>)
.addEventListener(eventname, callback)
.removeEventListener(callback)
.dispatchEvent(eventname)
.EMPTY = 0
.LOADING = 1
.DONE = 2
.error = undefined
.readyState = self.EMPTY
.result = undefined
- start
- progress
- error
- load
- end
- abort
- data // non-standard
end
{ target:
{ nodeBufferResult: <Buffer> // non-standard
, result: <Buffer|Binary|Text|DataURL>
}
}
progress
{ lengthComputable: (!isNaN(file.size)) ? true : false
, loaded: buffers.dataLength
, total: file.size
}
.on(eventname, callback)
.nodeChunkedEncoding = false
.setNodeChunkedEncoding(<Boolean>)
FileReader.setNodeChunkedEncoding() is a non-standard method which hints that the FileReader
should chunk if possible
I.E. The file will be sent with the header Transfer-Encoding: chunked
The default is false
since many webservers do not correctly implement the standard correctly,
and hence do not expect or accept Transfer-Encoding: chunked
from clients.
FileReader.on is a non-standard alias of addEventListener
EventTarget.target.nodeBufferResult is a non-standard property which is a Node.Buffer
instance of the data.
FileReader.on('data', fn) is a non-standard event which passes a Node.Buffer
chunk each time the progress
event is fired.