react-native-fs icon indicating copy to clipboard operation
react-native-fs copied to clipboard

`writeFile` on Android Simulator will not overwrite an existing file, but write over it

Open pedrosimao opened this issue 5 years ago • 13 comments

I am using the RNFS.writeFile(path, myObject, 'utf8'); method to write on a file specified by path. It works perfectly on iOS, but on Android Simulator it behaves strangely. When I use the command to write on a file that already exists, it will not completely overwrite the existing file, but it will write over it, keeping the existing content/string. The consequence is that if the existing file has a longer string than the string I am trying to write, the end of the string will be a broken thing, very weird.

I have tried to do exists() and unlink() in case the file exists before writing and it eliminates the bug. But the app becomes slower and if the user writes too fast I get some other annoying bugs because file does not exists when I try to read it.

Did anyone else had the same trouble as me?

pedrosimao avatar Jun 26 '19 11:06 pedrosimao

Finally, I solved the issue by ditching react-native-fs and using rn-fetch-blob instead. I couldn't afford to wait for the issue in this lib to be fixed. Hope the issue will be investigated anyway.

pedrosimao avatar Jun 28 '19 10:06 pedrosimao

@pedrosimao I am experiencing a similar issue but only on Android Q (API 29), on older versions it looks fine, could you tell which version were you using, so we could narrow down the problem?

gpawlik avatar Jul 30 '19 10:07 gpawlik

@pedrosimao @gpawlik Just running into this now as well on Android Q. Any luck with it?

META-DREAMER avatar Aug 30 '19 00:08 META-DREAMER

Occurring for me as well. Pixel 2, Android 10, physical device.

sbaruth avatar Dec 03 '19 16:12 sbaruth

I am not a developer, but this sounds like the same behaviour I see in the Joplin Android app when using local storage sync on Android 10.

Whenever I delete information from a note, the same number of characters stay appended to the end of the file, causing the sync process to fail.

I have an original Pixel XL and a Pixel 3a XL, both running Android 10.

rogerm4242 avatar Dec 10 '19 14:12 rogerm4242

Same issue here with production app, all devices running Android 10 - not writing over the whole file, but only the part that overlaps - i.e. if I want to write 100 symbols to a 120-symbol file, only the first 100 are overwritten and the rest remain, which in my case break the app. Devices include Samsung Note-s, OnePlus, Nokia, Huawei etc. all that have A10 updated. Might be a change in the the Android 10 API that is used in this package.

The fix that I used, because I really needed to fix the production was - with each write, first delete the file: RNFS.unlink(path).then(() => { RNFS.writeFile(path, content)); });

It is dirty as hell, and not really sure what the performance hit is, but it works, at least to patch the production app.

mstratiev avatar Jan 03 '20 18:01 mstratiev

I forgot to mention that in order to be safe when using this hacky workaround, I added an async queue to adapter that I am using for writing the files - meaning that a second write would not start executing before the unlink and write are finalized (in order to eliminate the race condition).

And that is acceptable in my case when I am doing rare writes to very few files.

mstratiev avatar Jan 08 '20 10:01 mstratiev

I am also encountering this issue in our production app, only in Android 10. previous android versions work fine.

I am wondering if it is to do with this line in RNFSManager.java getOutputStream method:

stream = reactContext.getContentResolver().openOutputStream(uri, append ? "wa" : "w");

according to documentation, the 'w' access mode passed as the second parameter of openOutputStream is supposed to give "write-only access (erasing whatever data is currently in the file)"

Another access mode option listed in the documentation is "rwt" which gives: "read and write access that truncates any existing file" So I replaced "w" with "rwt":

stream = reactContext.getContentResolver().openOutputStream(uri, append ? "wa" : "rwt");

From my limited tests, this change appears to work, it overwrites the file, and does not leave the extra trailing data.

Can anyone else give their opinion/insight on this? I am not completely familiar with Android and Java and file I/O.

silverInfinity avatar Jan 13 '20 23:01 silverInfinity

Found this issue on the android bug tracker: https://issuetracker.google.com/issues/135714729 They confirm that in order to truncate the file, you need to pass "t" in the access mode

silverInfinity avatar Jan 14 '20 02:01 silverInfinity

I found this issue on Actual Device as well. It just creates random pdf of existing file and new data.

quantumarun avatar Jun 09 '21 18:06 quantumarun

Couldn't wait for react-native-fs to release a new version (greater than 2.18.0), so i pushed a new npm package with the latest code from react-native-fs into react-native-fs-rwt

FlushNorris avatar Nov 10 '21 09:11 FlushNorris

I think this can be closed now as it seems to have been fixed in a recent version: https://github.com/itinance/react-native-fs/blob/master/android/src/main/java/com/rnfs/RNFSManager.java#L118-L126 Notice that it's now using "wrt" depending on Android version.

This was released in version 2.20.0: https://github.com/itinance/react-native-fs/commit/b7c7bf03481ee4f74f80cceb843267c05e9a3b9c

@pedrosimao should we close?

scarlac avatar Aug 10 '22 17:08 scarlac

This is still an issue for me on 2.20.0. On ios it works fine, but android the file does not overwrite

nica0012 avatar Sep 30 '23 23:09 nica0012