expo-file-system
Caminhos com sandbox, downloads e migração da API FS legada - o cookbook expo-file-system para aplicativos Expo SDK 57 que armazenam PDFs, fotos e payloads offline no dispositivo.
Busque em todas as páginas da documentação
Caminhos com sandbox, downloads e migração da API FS legada - o cookbook expo-file-system para aplicativos Expo SDK 57 que armazenam PDFs, fotos e payloads offline no dispositivo.
Cartão de receita de referência rápida - pronto para copiar e colar.
npx expo install expo-file-systemimport { Directory, File, Paths } from "expo-file-system";
export function ensureDownloadDir() {
const dir = new Directory(Paths.cache, "downloads");
if (!dir.exists) {
dir.create();
}
return dir;
}
export async function downloadPdf(url: string, filename: string) {
const dir = ensureDownloadDir();
const output = await File.downloadFileAsync(url, dir);
return output.uri;
}
export function writeJsonCache(name: string, data: unknown) {
const file = new File(Paths.cache, `${name}.json`);
if (!file.exists) {
file.create();
}
file.write(JSON.stringify(data));
}Quando usar isso:
File.createUploadTask.Quando evitar:
Download com progresso, metadados JSON auxiliares e interoperabilidade legada durante a migração.
npx expo install expo-file-system// src/files/downloadWithProgress.ts
import { Directory, File, Paths } from "expo-file-system";
export async function downloadInspectionPdf(
url: string,
jobId: string,
onProgress: (ratio: number) => void
) {
const dir = new Directory(Paths.document, "inspections", jobId);
if (!dir.exists) {
dir.create({ intermediates: true });
}
const destination = new File(dir, "report.pdf");
const task = File.createDownloadTask(url, destination, {
onProgress: ({ bytesWritten, totalBytes }) => {
if (totalBytes > 0) {
onProgress(bytesWritten / totalBytes);
}
},
});
const file = await task.downloadAsync();
if (!file) throw new Error("Download paused or cancelled");
const meta = new File(dir, "meta.json");
meta.create();
meta.write(JSON.stringify({ url, downloadedAt: Date.now() }));
return file.uri;
}// src/files/listInspections.ts
import { Directory, Paths } from "expo-file-system";
export function listInspectionJobIds(): string[] {
const root = new Directory(Paths.document, "inspections");
if (!root.exists) return [];
return root
.list()
.filter((entry) => entry instanceof Directory)
.map((d) => d.name);
}// src/files/legacyRead.ts - ponte temporária
import * as FileSystem from "expo-file-system/legacy";
import { File, Paths } from "expo-file-system";
export async function readLegacyManifest() {
const file = new File(Paths.cache, "legacy-manifest.json");
if (!file.exists) return null;
const text = await FileSystem.readAsStringAsync(file.uri);
return JSON.parse(text) as { version: number };
}O que isso demonstra:
Paths.document para PDFs significativos para o usuário - sobrevive a varreduras de cache.createDownloadTask com callback de progresso para barras de UI.Directory.list() para enumerar pastas de trabalhos.| Caminho | Persistência | Uso Típico |
|---|---|---|
Paths.document | Até a desinstalação do aplicativo | Exportações do usuário, PDFs de inspeção |
Paths.cache | O SO pode remover | Miniaturas, downloads temporários |
Paths.bundle | Ativos empacotados somente leitura | Arquivos iniciais no primeiro lançamento |
import { Paths } from "expo-file-system";
console.log(Paths.document.uri);
console.log(Paths.cache.uri);file.exists.const dir = new Directory(Paths.cache, "avatars");
dir.create({ intermediates: true });
const avatar = dir.createFile("user-42.jpg", "image/jpeg");
avatar.write(bytes);
const copy = new File(Paths.cache, "avatars", "user-42-copy.jpg");
avatar.copy(copy);
avatar.move(new Directory(Paths.document, "archive"));file://.exists antes da leitura - erros são para tipo de Arquivo/Diretório incorreto em caminhos existentes.textSync / bytesSync para arquivos pequenos - variantes assíncronas para cargas úteis grandes.// Download simples de uma vez
await File.downloadFileAsync(url, new Directory(Paths.cache, "pdfs"));
// Upload com progresso
const file = new File(Paths.document, "photo.jpg");
const task = file.createUploadTask("https://api.example.com/upload", {
uploadType: File.UploadType?.MULTIPART ?? 1,
onProgress: ({ bytesSent, totalBytes }) => {
console.log(bytesSent, totalBytes);
},
});
await task.uploadAsync();expo/fetch com corpo File para multipart quando as opções de tarefa de upload forem excessivas.// Antes (legado)
import * as FileSystem from "expo-file-system/legacy";
await FileSystem.readAsStringAsync(uri);
// Depois (SDK 57)
import { File } from "expo-file-system";
const file = new File(uri);
const text = file.textSync();expo-file-system/legacy apenas em locais de chamada não migrados.File a partir de strings de URI legadas - new File(existingUri).npx expo doctor e grep não mostrarem mais importações /legacy.{
"expo": {
"plugins": [
[
"expo-file-system",
{
"enableFileSharing": true,
"supportsOpeningDocumentsInPlace": true
}
]
]
}
}documentDirectory - útil para PDFs exportados.Paths.document.new File(Paths.cache, "a", "b.txt").bytes() / streams assíncronos.intermediates: true - create() aninhado falha. Correção: { intermediates: true } em caminhos profundos.| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
API File / Directory | Novo código SDK 57 | Manutenção de aplicativos SDK 54 sem largura de banda de migração |
expo-file-system/legacy | Módulos não migrados | Recursos Greenfield |
expo-sqlite | Linhas relacionais | Grandes blobs binários |
AsyncStorage | Preferências JSON pequenas | Arquivos maiores que alguns KB |
npx expo install expo-file-systemImporte { File, Directory, Paths } de expo-file-system - não apenas o namespace padrão.
Paths.cache na atualização da versão do aplicativo ou em uma ação de configurações.import { File, Paths } from "expo-file-system";
const seed = new File(Paths.bundle, "seed-data.json");const dir = new Directory(Paths.document, "inspections", jobId);
if (dir.exists) dir.delete(); // recursivoVersões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026