Native file and directory pickers for user-initiated file selection with platform-specific behaviors, MIME type filtering, and integration with system file managers.
Open native file selection dialogs for user-driven file access.
/**
* Opens a file picker for user file selection
* @param initialUri Optional initial directory path for picker
* @param mimeType Optional MIME type filter for selectable files
* @returns Promise resolving to selected File instance or array of Files
*/
static pickFileAsync(initialUri?: string, mimeType?: string): Promise<File | File[]>;Usage Examples:
import { File } from "expo-file-system";
// Basic file picker
async function selectFile() {
try {
const selectedFile = await File.pickFileAsync();
if (Array.isArray(selectedFile)) {
console.log(`Selected ${selectedFile.length} files:`);
selectedFile.forEach(file => {
console.log(`- ${file.name} (${file.size} bytes)`);
});
return selectedFile;
} else {
console.log(`Selected file: ${selectedFile.name}`);
console.log(`Size: ${selectedFile.size} bytes`);
console.log(`Type: ${selectedFile.type}`);
return [selectedFile];
}
} catch (error) {
console.log("User cancelled file selection");
return [];
}
}
// Image picker with MIME type filter
async function selectImage() {
try {
const imageFile = await File.pickFileAsync(undefined, "image/*");
if (Array.isArray(imageFile)) {
return imageFile[0]; // Take first image if multiple selected
}
console.log(`Selected image: ${imageFile.name}`);
console.log(`Image type: ${imageFile.type}`);
return imageFile;
} catch (error) {
console.error("Image selection failed:", error);
return null;
}
}
// Document picker with specific MIME types
async function selectDocument() {
const documentTypes = [
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"text/plain"
].join(",");
try {
const document = await File.pickFileAsync(undefined, documentTypes);
if (Array.isArray(document)) {
console.log(`Selected ${document.length} documents`);
return document;
}
console.log(`Selected document: ${document.name}`);
return [document];
} catch (error) {
console.log("Document selection cancelled");
return [];
}
}Open native directory selection dialogs for folder access (Android only).
/**
* Opens a directory picker for user directory selection
* @param initialUri Optional initial directory path for picker
* @returns Promise resolving to selected Directory instance
* @platform android
*/
static pickDirectoryAsync(initialUri?: string): Promise<Directory>;Usage Examples:
import { Directory } from "expo-file-system";
import { Platform } from "react-native";
// Directory picker with platform check
async function selectDirectory(): Promise<Directory | null> {
if (Platform.OS !== 'android') {
console.warn("Directory picker is only available on Android");
return null;
}
try {
const selectedDirectory = await Directory.pickDirectoryAsync();
console.log(`Selected directory: ${selectedDirectory.uri}`);
console.log(`Directory name: ${selectedDirectory.name}`);
// List contents of selected directory
const contents = selectedDirectory.list();
console.log(`Directory contains ${contents.length} items`);
return selectedDirectory;
} catch (error) {
console.log("User cancelled directory selection");
return null;
}
}
// Directory picker with initial location
async function selectDirectoryWithInitial(initialPath: string): Promise<Directory | null> {
if (Platform.OS !== 'android') {
return null;
}
try {
const selectedDirectory = await Directory.pickDirectoryAsync(initialPath);
return selectedDirectory;
} catch (error) {
console.error("Directory selection failed:", error);
return null;
}
}
// Usage examples
async function demonstrateDirectoryPicker() {
// Basic directory selection
const userDirectory = await selectDirectory();
if (userDirectory) {
// Work with selected directory
const files = userDirectory.list().filter(item => item instanceof File);
console.log(`Found ${files.length} files in selected directory`);
}
// Select with initial path
const documentsDirectory = await selectDirectoryWithInitial("/storage/emulated/0/Documents");
if (documentsDirectory) {
console.log(`Selected from Documents: ${documentsDirectory.name}`);
}
}Advanced file selection with type filtering and content validation.
Usage Examples:
import { File } from "expo-file-system";
// Media file picker with validation
async function selectMediaFile(): Promise<File | null> {
try {
const mediaFile = await File.pickFileAsync(undefined, "image/*,video/*,audio/*");
if (Array.isArray(mediaFile)) {
return mediaFile[0];
}
// Validate file size (e.g., max 50MB for media)
const maxSize = 50 * 1024 * 1024;
if (mediaFile.size > maxSize) {
console.error(`File too large: ${mediaFile.size} bytes (max: ${maxSize})`);
return null;
}
// Validate file type
const allowedTypes = ['image/jpeg', 'image/png', 'video/mp4', 'audio/mp3'];
if (!allowedTypes.includes(mediaFile.type)) {
console.error(`Unsupported file type: ${mediaFile.type}`);
return null;
}
console.log(`Valid media file selected: ${mediaFile.name}`);
return mediaFile;
} catch (error) {
console.error("Media file selection failed:", error);
return null;
}
}
// CSV/Excel file picker with content preview
async function selectDataFile(): Promise<{ file: File; preview: string } | null> {
const dataTypes = "text/csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
try {
const dataFile = await File.pickFileAsync(undefined, dataTypes);
const file = Array.isArray(dataFile) ? dataFile[0] : dataFile;
// Read first few lines for preview (CSV files)
if (file.type === 'text/csv' || file.extension === '.csv') {
const content = await file.text();
const lines = content.split('\n').slice(0, 5); // First 5 lines
const preview = lines.join('\n');
console.log("CSV Preview:");
console.log(preview);
return { file, preview };
}
return { file, preview: `File: ${file.name} (${file.size} bytes)` };
} catch (error) {
console.log("Data file selection cancelled");
return null;
}
}
// Configuration file picker with validation
async function selectConfigFile(): Promise<File | null> {
try {
const configFile = await File.pickFileAsync(undefined, "application/json,text/xml,text/yaml");
const file = Array.isArray(configFile) ? configFile[0] : configFile;
// Validate file content based on extension
const content = await file.text();
if (file.extension === '.json') {
try {
JSON.parse(content);
console.log("Valid JSON configuration file");
} catch (e) {
console.error("Invalid JSON format");
return null;
}
} else if (file.extension === '.xml') {
// Basic XML validation
if (!content.includes('<?xml') || !content.includes('<')) {
console.error("Invalid XML format");
return null;
}
}
return file;
} catch (error) {
console.error("Configuration file selection failed:", error);
return null;
}
}Complete workflows for file selection, processing, and storage.
Usage Examples:
import { File, Directory, Paths } from "expo-file-system";
// Image processing workflow
async function imageProcessingWorkflow(): Promise<File | null> {
// Step 1: Select image
const selectedImage = await File.pickFileAsync(undefined, "image/jpeg,image/png");
if (!selectedImage || Array.isArray(selectedImage)) {
console.log("No image selected");
return null;
}
console.log(`Processing image: ${selectedImage.name}`);
// Step 2: Create processing directory
const processingDir = new Directory(Paths.document, "processed-images");
processingDir.create({ idempotent: true });
// Step 3: Copy to processing directory
const processedImage = new File(
processingDir,
`processed-${Date.now()}-${selectedImage.name}`
);
selectedImage.copy(processedImage);
// Step 4: Add metadata file
const metadataFile = new File(
processingDir,
`${processedImage.name}.metadata.json`
);
const metadata = {
originalName: selectedImage.name,
originalSize: selectedImage.size,
processedAt: new Date().toISOString(),
originalType: selectedImage.type
};
metadataFile.write(JSON.stringify(metadata, null, 2));
console.log(`Image processing completed: ${processedImage.name}`);
return processedImage;
}
// Document import workflow
async function documentImportWorkflow(): Promise<File[]> {
const importedFiles: File[] = [];
// Step 1: Select documents (potentially multiple)
const selectedFiles = await File.pickFileAsync(
undefined,
"application/pdf,application/msword,text/plain"
);
const files = Array.isArray(selectedFiles) ? selectedFiles : [selectedFiles];
// Step 2: Create import directory with timestamp
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const importDir = new Directory(Paths.document, "imports", timestamp);
importDir.create({ intermediates: true });
// Step 3: Process each file
for (const file of files) {
console.log(`Importing: ${file.name}`);
// Create safe filename
const safeFilename = file.name.replace(/[^a-zA-Z0-9.-]/g, '_');
const importedFile = new File(importDir, safeFilename);
// Copy file
file.copy(importedFile);
// Create import record
const importRecord = {
originalPath: file.uri,
importedPath: importedFile.uri,
originalSize: file.size,
importedAt: new Date().toISOString(),
checksum: file.info({ md5: true }).md5
};
const recordFile = new File(importDir, `${safeFilename}.import.json`);
recordFile.write(JSON.stringify(importRecord, null, 2));
importedFiles.push(importedFile);
}
// Step 4: Create import summary
const summary = {
importId: timestamp,
fileCount: importedFiles.length,
totalSize: importedFiles.reduce((sum, file) => sum + file.size, 0),
files: importedFiles.map(file => ({
name: file.name,
size: file.size,
type: file.type
}))
};
const summaryFile = new File(importDir, "import-summary.json");
summaryFile.write(JSON.stringify(summary, null, 2));
console.log(`Import completed: ${importedFiles.length} files imported`);
return importedFiles;
}
// Backup and restore workflow
async function backupWorkflow(): Promise<File | null> {
// Select directory to backup (Android only)
if (Platform.OS !== 'android') {
console.log("Backup workflow requires Android for directory selection");
return null;
}
try {
// Step 1: Select source directory
const sourceDir = await Directory.pickDirectoryAsync();
console.log(`Backing up directory: ${sourceDir.name}`);
// Step 2: Create backup location
const backupDir = new Directory(Paths.document, "backups");
backupDir.create({ idempotent: true });
// Step 3: Create backup with timestamp
const timestamp = new Date().toISOString().split('T')[0];
const backupName = `${sourceDir.name}-backup-${timestamp}`;
const targetBackupDir = new Directory(backupDir, backupName);
// Step 4: Copy directory contents
sourceDir.copy(targetBackupDir);
// Step 5: Create backup manifest
const manifest = {
backupId: backupName,
sourceDirectory: sourceDir.uri,
backupDirectory: targetBackupDir.uri,
createdAt: new Date().toISOString(),
fileCount: targetBackupDir.list().length
};
const manifestFile = new File(backupDir, `${backupName}.manifest.json`);
manifestFile.write(JSON.stringify(manifest, null, 2));
console.log(`Backup completed: ${backupName}`);
return manifestFile;
} catch (error) {
console.error("Backup workflow failed:", error);
return null;
}
}
// Usage demonstration
async function demonstrateWorkflows() {
console.log("=== Image Processing Workflow ===");
const processedImage = await imageProcessingWorkflow();
console.log("\n=== Document Import Workflow ===");
const importedDocs = await documentImportWorkflow();
console.log("\n=== Backup Workflow ===");
const backupManifest = await backupWorkflow();
return {
processedImage,
importedDocs,
backupManifest
};
}Handle platform differences and optimize picker behavior.
Usage Examples:
import { File, Directory } from "expo-file-system";
import { Platform } from "react-native";
// Platform-adaptive file picker
class PlatformFilePicker {
static async pickFile(options: {
mimeTypes?: string[];
multiple?: boolean;
initialDirectory?: string;
} = {}): Promise<File[]> {
const mimeType = options.mimeTypes?.join(',');
try {
if (Platform.OS === 'ios') {
// iOS-specific behavior
console.log("Using iOS file picker");
const result = await File.pickFileAsync(options.initialDirectory, mimeType);
return Array.isArray(result) ? result : [result];
} else if (Platform.OS === 'android') {
// Android-specific behavior
console.log("Using Android file picker");
const result = await File.pickFileAsync(options.initialDirectory, mimeType);
return Array.isArray(result) ? result : [result];
} else {
throw new Error(`Unsupported platform: ${Platform.OS}`);
}
} catch (error) {
console.log("File picker cancelled or failed");
return [];
}
}
static async pickDirectory(initialPath?: string): Promise<Directory | null> {
if (Platform.OS !== 'android') {
console.warn("Directory picker only available on Android");
// Could implement alternative for iOS using document picker
return null;
}
try {
return await Directory.pickDirectoryAsync(initialPath);
} catch (error) {
console.log("Directory picker cancelled");
return null;
}
}
}
// Cross-platform file access patterns
async function crossPlatformFileAccess() {
// Adapt picker behavior to platform capabilities
const files = await PlatformFilePicker.pickFile({
mimeTypes: ['image/jpeg', 'image/png'],
multiple: Platform.OS === 'android' // Multiple selection on Android
});
console.log(`Selected ${files.length} files`);
// Platform-specific directory access
let workingDirectory: Directory | null = null;
if (Platform.OS === 'android') {
// Use directory picker on Android
workingDirectory = await PlatformFilePicker.pickDirectory();
} else {
// Use predefined directory on iOS
workingDirectory = new Directory(Paths.document, "user-files");
workingDirectory.create({ idempotent: true });
}
if (workingDirectory) {
console.log(`Working with directory: ${workingDirectory.name}`);
// Process selected files in working directory
for (const file of files) {
const targetFile = new File(workingDirectory, file.name);
file.copy(targetFile);
console.log(`Copied ${file.name} to working directory`);
}
}
}
// Usage
await crossPlatformFileAccess();