apache / apache/cordova-plugin-file
Application crash with big data (JSON)
- Dominant language
- JavaScript
- Stars
- 744
- Forks
- 754
- Avg merge
- 3d 4h
- Merged PRs (30d)
- 1
Description
# Bug Report
## Problem
### What is expected to happen?
The (big) data is correctly written in the file.
### What does actually happen?
The application crashes.
### 💡
I found a workaround but I think it remains an issue in the codebase (and could impact other developers). See below for the workaround.
## Information
I use:
* cordova-plugin-file
* react-native
* redux-persist
For the persistance (with redux-persist), I have a custom storage handler to write into a file.
The write part is very simple :
```typescript
function writeFile(fileEntry: FileEntry, data: any): Promise {
return new Promise((resolve, reject) => {
fileEntry.createWriter(writer => {
writer.onerror = reject
writer.onwriteend = resolve
writer.write(new Blob([JSON.stringify(data)], { type: 'text/plain' }))
}, reject)
})
}
```
However, with an evolution, our `data` passed from ~2Mo to ~20Mo. At this moment, the application crashes when saving the file.
It is the call to `writer.write` which seemed to cause the application to crash, if I build the Blob without saving it, I do not have any issue.
The size of the data before crash differs from IOS and ipad version.
### Workaround
I corrected (quick-win) the issue by doing so:
```typescript
function writeFile(fileEntry: FileEntry, data: any): Promise {
return new Promise((resolve, reject) => {
fileEntry.createWriter(writer => {
splitByChunks(JSON.stringify(data), 1000 * 1000) // 1Mo
// Ensure order of execution, could be improved
.reduce((acc, chunk) => acc.then(() => writeChunk(writer, chunk)), Promise.resolve())
.then(resolve)
.catch(reject)
}, reject)
})
}
function writeChunk(writer: FileWriter, chunk: string): Promise {
return new Promise((resolve, reject) => {
writer.onerror = reject
writer.onwriteend = resolve
writer.write(new Blob([chunk], { type: 'text/plain' }))
})
}
function splitByChunks(value: string, chunkLength: number): ReadonlyArray {
return Array(Math.ceil(value.length / chunkLength))
.fill(0)
.map((_, index) => value.slice(index * chunkLength, (index + 1) * chunkLength))
}
```
Although this correction works in my project there is an issue when the file is not totally written (application closed during write). I resolved it by ignoring incomplete file (= `JSON.parse` fails) because my project permits it.
### Environment, Platform, Device
* ipad4 / ios10
* ipad5 / ios12
* ipad6 / ios12
### Version information
* cordova: 8.1.2
* "cordova-browser": "5.0.1", // also tested on v6.0.1 - same issue
* "cordova-ios": "4.5.4",
* "cordova-plugin-file": "5.0.0",
## Checklist
- [x] I searched for existing GitHub issues
* Maybe related: #291, #297
- [x] I updated all Cordova tooling to most recent version
* But rolled back because of some incompatibilities in other parts of the application, issue still happening in last versions
- [x] I included all the necessary information above
Thanks for the plugin! 👍
Contributor guide
Research direction
No source file or test is named in the report. Start by reproducing the crash at writer.write with roughly 20 MB of JSON on the listed iOS versions, comparing a single Blob write with the chunked workaround. Done means large data can be written without the application crashing and the resulting file remains complete.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ios, javascript, react-native, typescript
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100