React-native-fetch-blob: Can I use RNFetchBlob with "path" config to save to local file system?

Created on 11 Sep 2016  路  7Comments  路  Source: wkh237/react-native-fetch-blob

Hi... I want to save users image thumbnails to the file system in react native. (think of a chat app, with small round images). I want those images to be saved to local file system, so in the next time they will be loaded directly from file system (and not downloaded again).

So I look at this code:

let dirs = RNFetchBlob.fs.dirs
RNFetchBlob
.config({
  // response data will be saved to this path if it has access right.
  path : dirs.DocumentDir + '/userThumbnails/12dfg472kadf4.png'
})
.fetch('GET', 'http://www.example.com/file/example.zip', {
  //some headers ..
})
.then((res) => {
  // the path should be dirs.DocumentDir + 'path-to-file.anything'
  console.log('The file saved to ', res.path())
})

This code will happen once when first downloading the image.
Will this code write the file 12dfg472kadf4.png to the file system?
I do not want it to be a cached file or something like that. I want it to be a regular file sitting in the file system, persisted, which I can use as a src property for an from now on.
Am I correct?

needs feedback task

Most helpful comment

@yaronlevi , thanks for your advice 馃槃 I'll add it to the document.

fileCache : true is similar to path: ... they both store the response data in file system. The only difference is the former uses a random generated file name which will always located in DocumentDir and the later uses a customized location.

On IOS DocumentDir is the Documents/ folder under app's bundle, here's the description from Apple Developer

Use this directory to store user-generated content. The contents of this directory can be made available to the user through file sharing; therefore, his directory should only contain files that you may wish to expose to the user.
The contents of this directory are backed up by iTunes.

The files will persist unless you remove the app or the file by fs.unlink, if you're looking for cache folder which files will removed by system, consider use CacheDir, here's the description from Apple Developer

Use this directory to write temporary files that do not need to persist between launches of your app. Your app should remove files from this directory when they are no longer needed; however, the system may purge this directory when your app is not running.
The contents of this directory are not backed up by iTunes.

(On IOS, files in CacheDir will not removed when app is active)

As for Android, when you store file in DocumentDir it's using File.getFilesDir() under the hood, the file will also persist until it's removed. Generally the file will be stored in internal storage.

When using CacheDir on Android, it uses File.getCacheDir, from Google Developers

These files will be ones that get deleted first when the device runs low on storage. There is no guarantee when these files will be deleted. Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space. The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted.

All 7 comments

Yeah, I think the usage is correct, but it's recommended to make sure that dirs.DocumentDir + '/userThumbnails/ exists by using our fs API. Besides, the our network module has default cache mechanism, which might result in unexpected behavior, to disable it, you can simply set a Cache Control Header, for example

RNFetchBlob
    .config({ path : RNFetchBlob.fs.dirs.DocumentDir + '/userThumbnails/user.png' +  })
    .fetch('GET', 'http://example.com/file/', {
        'Cache-Control' : 'no-store'
    })
    .then((res) => {
        res.path() // where the file is
    })

Hope this is helpful for you, please feel give us any feedback if there's any problem, thank you 馃槃

Ok great! I will try it and come back with results.
Good thing you mentioned the Cache-Control thingy. It probably will save me few burnt days (-:
Though I am little confused with "fileCache:true" config. They are not the same?
Maybe an entry in the docs regarding Cache-Control would help fellow programmers.

@yaronlevi , thanks for your advice 馃槃 I'll add it to the document.

fileCache : true is similar to path: ... they both store the response data in file system. The only difference is the former uses a random generated file name which will always located in DocumentDir and the later uses a customized location.

On IOS DocumentDir is the Documents/ folder under app's bundle, here's the description from Apple Developer

Use this directory to store user-generated content. The contents of this directory can be made available to the user through file sharing; therefore, his directory should only contain files that you may wish to expose to the user.
The contents of this directory are backed up by iTunes.

The files will persist unless you remove the app or the file by fs.unlink, if you're looking for cache folder which files will removed by system, consider use CacheDir, here's the description from Apple Developer

Use this directory to write temporary files that do not need to persist between launches of your app. Your app should remove files from this directory when they are no longer needed; however, the system may purge this directory when your app is not running.
The contents of this directory are not backed up by iTunes.

(On IOS, files in CacheDir will not removed when app is active)

As for Android, when you store file in DocumentDir it's using File.getFilesDir() under the hood, the file will also persist until it's removed. Generally the file will be stored in internal storage.

When using CacheDir on Android, it uses File.getCacheDir, from Google Developers

These files will be ones that get deleted first when the device runs low on storage. There is no guarantee when these files will be deleted. Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space. The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted.

It works like charm!
I wrapped it in a Promise:

downloadFileFromUrlToPath(url, path) {
        return new Promise(function (resolve, reject) {
            FetchBlob
                .config({ path })
                .fetch('GET', url, {
                    'Cache-Control': 'no-store'
                })
                .then((res) => {
                    resolve();
                })
                .catch((err) => {
                    reject(err);
                })
        });
    }

And then called it from a redux-saga:
yield call(FetchBlobSrv.downloadFileFromUrlToPath, url, imageLocalUri);

@yaronlevi fetch() is already returning a promise, see here:

downloadFileFromUrlToPath(url, path) {
    return FetchBlob.config({ path }).fetch('GET', url, { 'Cache-Control': 'no-store'})
}

oh you're right, thanks.

@wkh237 I was under the impression RNFetchBlob used the "do not back up" flag on iOS when storing files using the "path" rnfetchblobconfig setting. As such even files written to CacheDir would remain untouched by system garbage collection and so they would only be removed by explicitly unlinking the files. Is this true? Or am I at risk of local files saved to CacheDir using the "path" config setting being removed by the OS periodically?

https://developer.apple.com/icloud/documentation/data-storage/index.html

Was this page helpful?
0 / 5 - 0 ratings

Related issues

timsuchanek picture timsuchanek  路  4Comments

sivakumar-cf picture sivakumar-cf  路  4Comments

mykelaballe picture mykelaballe  路  4Comments

nicholasstephan picture nicholasstephan  路  3Comments

Draccan picture Draccan  路  3Comments