Skip to main content
Glama
filesystem.md9.62 kB
--- title: FileSystem description: A library that provides access to the local file system on the device. sourceCodeUrl: https://github.com/expo/expo/tree/sdk-52/packages/expo-file-system packageName: expo-file-system iconUrl: /static/images/packages/expo-file-system.png platforms: ["android", "ios", "tvos"] --- `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. Within Expo Go, each project has a separate file system scope and has no access to the file system of other projects. ## Installation ## Usage ### Downloading files ```js Component.js 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 ```js 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 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 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 return FileSystem.getContentUriAsync(await getSingleGif(gifId)); } // Deletes whole giphy directory with all its content 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: ```js index.js 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 ```js ``` ### 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: - [`FileSystem.documentDirectory`](#filesystemdocumentdirectory) - [`FileSystem.cacheDirectory`](#filesystemcachedirectory) 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`](#requestdirectorypermissionsasyncinitialfileurl) method. ## 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:///`,<br/>`content://`,<br/>`asset://`,<br/>no scheme | `file://`,<br/>`ph://`,<br/>`assets-library://` | | `readAsStringAsync` | `file:///`,<br/>`asset://`,<br/>[SAF URI](#saf-uri) | `file://` | | `writeAsStringAsync` | `file:///`,<br/>[SAF URI](#saf-uri) | `file://` | | `deleteAsync` | `file:///`,<br/>[SAF URI](#saf-uri) | `file://` | | `moveAsync` | Source:<br/>`file:///`,<br/>[SAF URI](#saf-uri)<br/><br/>Destination:<br/>`file://` | Source:<br/>`file://`<br/><br/>Destination:<br/>`file://` | | `copyAsync` | Source:<br/>`file:///`,<br/>`content://`,<br/>`asset://`,<br/>[SAF URI](#saf-uri),<br/>no scheme<br/><br/>Destination:<br/>`file://` | Source:<br/>`file://`,<br/>`ph://`,<br/>`assets-library://`<br/><br/>Destination:<br/>`file://` | | `makeDirectoryAsync` | `file:///` | `file://` | | `readDirectoryAsync` | `file:///` | `file://` | | `downloadAsync` | Source:<br/>`http://`,<br/>`https://`<br/><br/>Destination:<br/>`file:///` | Source:<br/>`http://`,<br/>`https://`<br/><br/>Destination:<br/>`file://` | | `uploadAsync` | Source:<br/>`file:///`<br/><br/>Destination:<br/>`http://`<br/>`https://` | Source:<br/>`file://`<br/><br/>Destination:<br/>`http://`<br/>`https://` | | `createDownloadResumable` | Source:<br/>`http://`,<br/>`https://`<br/><br/>Destination:<br/>`file:///` | Source:<br/>`http://`,<br/>`https://`<br/><br/>Destination:<br/>`file://` | > On Android **no scheme** defaults to a bundled resource. ## Permissions ### Android The following permissions are added automatically through this library's **AndroidManifest.xml**. ### iOS _No permissions required_.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaksm/expo-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server