This is documentation for the next SDK version. For up-to-date documentation, see the latest version (SDK 53).
Expo FileSystem (legacy)
A library that provides access to the local file system on the device.
Thelegacy
version of the FileSystem API is included in theexpo-file-system
library. It can be used alongside the modern API for backward compatibility reasons.
expo-file-system
provides access to a file system stored locally on the device. It is also capable of uploading and downloading files from network URLs.
How expo-file-system works differently inside of the Expo Go app
Within Expo Go, each project has a separate file system scope and has no access to the file system of other projects.
Installation
-
npx expo install expo-file-system
If you are installing this in an existing React Native app, make sure to install expo
in your project.
Usage
Downloading files
const callback = downloadProgress => { const progress = downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite; this.setState({ downloadProgress: progress, }); }; const downloadResumable = FileSystem.createDownloadResumable( 'http://techslides.com/demos/sample-videos/small.mp4', FileSystem.documentDirectory + 'small.mp4', {}, callback ); try { const { uri } = await downloadResumable.downloadAsync(); console.log('Finished downloading to ', uri); } catch (e) { console.error(e); } try { await downloadResumable.pauseAsync(); console.log('Paused download operation, saving for future retrieval'); AsyncStorage.setItem('pausedDownload', JSON.stringify(downloadResumable.savable())); } catch (e) { console.error(e); } try { const { uri } = await downloadResumable.resumeAsync(); console.log('Finished downloading to ', uri); } catch (e) { console.error(e); } //To resume a download across app restarts, assuming the DownloadResumable.savable() object was stored: const downloadSnapshotJson = await AsyncStorage.getItem('pausedDownload'); const downloadSnapshot = JSON.parse(downloadSnapshotJson); const downloadResumable = new FileSystem.DownloadResumable( downloadSnapshot.url, downloadSnapshot.fileUri, downloadSnapshot.options, callback, downloadSnapshot.resumeData ); try { const { uri } = await downloadResumable.resumeAsync(); console.log('Finished downloading to ', uri); } catch (e) { console.error(e); }
Managing Giphy's
import * as FileSystem from 'expo-file-system/legacy'; const gifDir = FileSystem.cacheDirectory + 'giphy/'; const gifFileUri = (gifId: string) => gifDir + `gif_${gifId}_200.gif`; const gifUrl = (gifId: string) => `https://media1.giphy.com/media/${gifId}/200.gif`; // Checks if gif directory exists. If not, creates it async function ensureDirExists() { const dirInfo = await FileSystem.getInfoAsync(gifDir); if (!dirInfo.exists) { console.log("Gif directory doesn't exist, creating…"); await FileSystem.makeDirectoryAsync(gifDir, { intermediates: true }); } } // Downloads all gifs specified as array of IDs export async function addMultipleGifs(gifIds: string[]) { try { await ensureDirExists(); console.log('Downloading', gifIds.length, 'gif files…'); await Promise.all(gifIds.map(id => FileSystem.downloadAsync(gifUrl(id), gifFileUri(id)))); } catch (e) { console.error("Couldn't download gif files:", e); } } // Returns URI to our local gif file // If our gif doesn't exist locally, it downloads it export async function getSingleGif(gifId: string) { await ensureDirExists(); const fileUri = gifFileUri(gifId); const fileInfo = await FileSystem.getInfoAsync(fileUri); if (!fileInfo.exists) { console.log("Gif isn't cached locally. Downloading…"); await FileSystem.downloadAsync(gifUrl(gifId), fileUri); } return fileUri; } // Exports shareable URI - it can be shared outside your app export async function getGifContentUri(gifId: string) { return FileSystem.getContentUriAsync(await getSingleGif(gifId)); } // Deletes whole giphy directory with all its content export async function deleteAllGifs() { console.log('Deleting all GIF files…'); await FileSystem.deleteAsync(gifDir); }
Server: handling multipart requests
The simple server in Node.js, which can save uploaded images to disk:
const express = require('express'); const app = express(); const fs = require('fs'); const multer = require('multer'); const upload = multer({ dest: 'uploads/' }); // This method will save the binary content of the request as a file. app.patch('/binary-upload', (req, res) => { req.pipe(fs.createWriteStream('./uploads/image' + Date.now() + '.png')); res.end('OK'); }); // This method will save a "photo" field from the request as a file. app.patch('/multipart-upload', upload.single('photo'), (req, res) => { // You can access other HTTP parameters. They are located in the body object. console.log(req.body); res.end('OK'); }); app.listen(3000, () => { console.log('Working on port 3000'); });
API
import * as FileSystem from 'expo-file-system/legacy';
Directories
The API takes file://
URIs pointing to local files on the device to identify files. Each app only has read and write access to locations under the following directories:
So, for example, the URI to a file named 'myFile'
under 'myDirectory'
in the app's user documents directory would be FileSystem.documentDirectory + 'myDirectory/myFile'
.
Expo APIs that create files generally operate within these directories. This includes Audio
recordings, Camera
photos, ImagePicker
results, SQLite
databases and takeSnapShotAsync()
results. This allows their use with the FileSystem
API.
Some FileSystem
functions are able to read from (but not write to) other locations.
SAF URI
A SAF URI is a URI that is compatible with the Storage Access Framework. It should look like this content://com.android.externalstorage.*
.
The easiest way to obtain such URI is by requestDirectoryPermissionsAsync
method.
No API data file found, sorry!
Supported URI schemes
In this table, you can see what type of URI can be handled by each method. For example, if you have an URI, which begins with content://
, you cannot use FileSystem.readAsStringAsync()
, but you can use FileSystem.copyAsync()
which supports this scheme.
Method name | Android | iOS |
---|---|---|
getInfoAsync | file:/// ,content:// ,asset:// ,no scheme | file:// ,ph:// ,assets-library:// |
readAsStringAsync | file:/// ,asset:// ,SAF URI | file:// |
writeAsStringAsync | file:/// ,SAF URI | file:// |
deleteAsync | file:/// ,SAF URI | file:// |
moveAsync | Source:file:/// ,SAF URI Destination: file:// | Source:file:// Destination: file:// |
copyAsync | Source:file:/// ,content:// ,asset:// ,SAF URI, no scheme Destination: file:// | Source:file:// ,ph:// ,assets-library:// Destination: file:// |
makeDirectoryAsync | file:/// | file:// |
readDirectoryAsync | file:/// | file:// |
downloadAsync | Source:http:// ,https:// Destination: file:/// | Source:http:// ,https:// Destination: file:// |
uploadAsync | Source:file:/// Destination: http:// https:// | Source:file:// Destination: http:// https:// |
createDownloadResumable | Source:http:// ,https:// Destination: file:/// | Source:http:// ,https:// Destination: file:// |
On Android no scheme defaults to a bundled resource.
Permissions
Android
The following permissions are added automatically through this library's AndroidManifest.xml.
Android Permission | Description |
---|---|
Allows an application to read from external storage. | |
Allows an application to write to external storage. | |
Allows applications to open network sockets. |
iOS
No permissions required.