Skip to content

A high-performance file system module for React Native that handles file operations and transfers with native speed.

Notifications You must be signed in to change notification settings

patrickkabwe/react-native-nitro-fs

Repository files navigation

React Native NitroFS

React Native NitroFS

A high-performance file system module for React Native that provides native-speed file operations and network transfers using Swift (iOS) and Kotlin (Android) implementations.

πŸš€ Features

  • πŸ“ File Operations: Read, write, copy, delete, and manage files
  • πŸ“‚ Directory Management: Create, navigate, and manage directories
  • ⬆️ File Uploads: Upload files with progress tracking and multipart support
  • ⬇️ File Downloads: Download files with progress tracking
  • πŸ” File Inspection: Check existence, get file stats, and list directory contents
  • ⚑ Native Performance: Direct Swift/Kotlin implementations for optimal speed
  • πŸ“± Cross-Platform: Full support for iOS and Android
  • πŸ›‘οΈ Error Handling: Comprehensive error handling with detailed messages
  • πŸ’Ύ Memory Efficient: Optimized for large files with chunked reading

πŸ“‹ Requirements

  • React Native: v0.78.0 or higher
  • Node.js: 18.0.0 or higher
  • Platforms: iOS 12.0+, Android API 21+

πŸ“¦ Installation

# Using bun (recommended)
bun add react-native-nitro-fs [email protected]

# Using npm
npm install react-native-nitro-fs [email protected]

# Using yarn
yarn add react-native-nitro-fs [email protected]

iOS Setup

cd ios && pod install

🎯 Quick Start

import { NitroFS } from 'react-native-nitro-fs'

// Basic file operations
const exists = await NitroFS.exists('/path/to/file')
const content = await NitroFS.readFile('/path/to/file', 'utf8')
await NitroFS.writeFile('/path/to/file', 'Hello, World!', 'utf8')

// Download with progress
const file = await NitroFS.downloadFile(
  'https://example.com/file.txt',
  NitroFS.DOWNLOAD_DIR + '/file.txt',
  (downloadedBytes, totalBytes) => {
    console.log(`Downloading ${(downloadedBytes / totalBytes) * 100}%`)
  }
)

// Upload with progress
await NitroFS.uploadFile(
  { name: 'file.txt', mimeType: 'text/plain', path: '/path/to/file.txt' },
  { url: 'https://example.com/upload', method: 'POST', field: 'file' },
  (uploadedBytes, totalBytes) => {
    console.log(`Uploading ${(uploadedBytes / totalBytes) * 100}%`)
  }
)

πŸ“š API Reference

Directory Constants

Access predefined directory paths for different use cases:

// Bundle directory (read-only, app resources)
NitroFS.BUNDLE_DIR

// Documents directory (user data, backed up)
NitroFS.DOCUMENT_DIR

// Cache directory (temporary data, not backed up)
NitroFS.CACHE_DIR

// Downloads directory (user downloads)
NitroFS.DOWNLOAD_DIR

File System Operations

exists(path: string): Promise<boolean>

Check if a file or directory exists at the specified path.

// Check if file exists
const fileExists = await NitroFS.exists('/path/to/file.txt')

// Check if directory exists
const dirExists = await NitroFS.exists('/path/to/directory')

writeFile(path: string, data: string, encoding: NitroFileEncoding): Promise<void>

Write data to a file. Creates parent directories automatically and performs atomic writes.

// Write text file
await NitroFS.writeFile(
  NitroFS.DOCUMENT_DIR + '/config.json',
  JSON.stringify({ theme: 'dark' }),
  'utf8'
)

// Write with different encoding
await NitroFS.writeFile('/path/to/file.txt', 'Hello World', 'utf8')

Features:

  • βœ… Automatic parent directory creation
  • βœ… Atomic write operations
  • βœ… Disk space validation
  • βœ… Comprehensive error handling

readFile(path: string, encoding: NitroFileEncoding): Promise<string>

Read the contents of a file with optimized memory handling for large files.

// Read text file
const content = await NitroFS.readFile('/path/to/file.txt', 'utf8')

// Read JSON file
const config = JSON.parse(
  await NitroFS.readFile('/path/to/config.json', 'utf8')
)

Performance Features:

  • πŸš€ Adaptive chunked reading for large files
  • πŸ’Ύ Memory-efficient handling
  • ⚠️ Automatic size limits for very large files

copyFile(srcPath: string, destPath: string): Promise<void>

Copy a file from source to destination.

// Copy file to documents directory
await NitroFS.copyFile(
  '/path/to/source.txt',
  NitroFS.DOCUMENT_DIR + '/backup.txt'
)

copy(srcPath: string, destPath: string): Promise<void>

Copy a file or directory recursively.

// Copy entire directory
await NitroFS.copy('/path/to/source', '/path/to/destination')

unlink(path: string): Promise<boolean>

Delete a file or directory.

// Delete file
await NitroFS.unlink('/path/to/file.txt')

// Delete directory (recursive)
await NitroFS.unlink('/path/to/directory')

mkdir(path: string): Promise<boolean>

Create a directory.

// Create single directory
await NitroFS.mkdir('/path/to/newdir')

// Create nested directories (handled automatically)
await NitroFS.mkdir('/path/to/nested/directories')

stat(path: string): Promise<NitroFileStat>

Get detailed information about a file or directory.

const stat = await NitroFS.stat('/path/to/file.txt')
console.log({
  size: stat.size, // File size in bytes
  isDirectory: stat.isDirectory,
  isFile: stat.isFile,
  modifiedTime: stat.mtime, // Last modified timestamp
  createdTime: stat.ctime, // Creation timestamp
})

readdir(path: string): Promise<string[]>

List contents of a directory.

// List all files and directories
const items = await NitroFS.readdir('/path/to/directory')
console.log('Directory contents:', items)

rename(oldPath: string, newPath: string): Promise<void>

Rename or move a file or directory.

// Rename file
await NitroFS.rename('/path/to/old.txt', '/path/to/new.txt')

// Move file to different directory
await NitroFS.rename('/path/to/file.txt', '/new/path/file.txt')

Path Utilities

dirname(path: string): string

Get the directory name from a path.

const dir = NitroFS.dirname('/path/to/file.txt')
// Returns: '/path/to'

basename(path: string, ext?: string): string

Get the filename from a path, optionally removing extension.

const name = NitroFS.basename('/path/to/file.txt')
// Returns: 'file.txt'

const nameWithoutExt = NitroFS.basename('/path/to/file.txt', '.txt')
// Returns: 'file'

extname(path: string): string

Get the file extension from a path.

const ext = NitroFS.extname('/path/to/file.txt')
// Returns: '.txt'

Network Operations

uploadFile(file: NitroFile, uploadOptions: NitroUploadOptions, onProgress?: (uploadedBytes: number, totalBytes: number) => void): Promise<void>

Upload a file to a server with progress tracking and multipart support.

const file = {
  name: 'document.pdf',
  mimeType: 'application/pdf',
  path: NitroFS.DOCUMENT_DIR + '/document.pdf',
}

const uploadOptions = {
  url: 'https://api.example.com/upload',
  method: 'POST',
  field: 'file',
  headers: {
    'Authorization': 'Bearer your-token',
    'X-Custom-Header': 'value',
  },
}

await NitroFS.uploadFile(file, uploadOptions, (uploadedBytes, totalBytes) => {
  const progress = (uploadedBytes / totalBytes) * 100
  console.log(`Upload progress: ${progress.toFixed(1)}%`)
})

downloadFile(serverUrl: string, destinationPath: string, onProgress?: (downloadedBytes: number, totalBytes: number) => void): Promise<NitroFile>

Download a file from a server with progress tracking.

const serverUrl = 'https://example.com/files/document.pdf'
const destinationPath = NitroFS.DOWNLOAD_DIR + '/document.pdf'

const downloadedFile = await NitroFS.downloadFile(
  serverUrl,
  destinationPath,
  (downloadedBytes, totalBytes) => {
    const progress = (downloadedBytes / totalBytes) * 100
    console.log(`Download progress: ${progress.toFixed(1)}%`)
  }
)

console.log('Downloaded file:', downloadedFile)
// Returns: { name: 'document.pdf', mimeType: 'application/pdf', path: '/path/to/file' }

πŸ“ Type Definitions

NitroFile

interface NitroFile {
  name: string // File name with extension
  mimeType: string // MIME type (e.g., 'text/plain', 'application/pdf')
  path: string // Full file path
}

NitroUploadOptions

interface NitroUploadOptions {
  url: string // Upload endpoint URL
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' // HTTP method
  field: string // Form field name
  headers?: Record<string, string> // Custom headers
}

NitroFileStat

interface NitroFileStat {
  size: number // File size in bytes
  isDirectory: boolean // True if path is a directory
  isFile: boolean // True if path is a file
  mtime: number // Last modified timestamp
  ctime: number // Creation timestamp
}

NitroFileEncoding

type NitroFileEncoding = 'utf8' | 'ascii' | 'base64'

πŸ”§ Advanced Usage

Error Handling

try {
  const content = await NitroFS.readFile('/path/to/file.txt', 'utf8')
  console.log('File content:', content)
} catch (error) {
  if (error.message.includes('File does not exist')) {
    console.log('File not found')
  } else if (error.message.includes('Permission denied')) {
    console.log('No permission to access file')
  } else {
    console.error('Unexpected error:', error.message)
  }
}

Working with Large Files

// The library automatically handles large files efficiently
const largeFile = await NitroFS.readFile('/path/to/large-file.txt', 'utf8')

// For very large files (>100MB), consider streaming or chunked processing
const stat = await NitroFS.stat('/path/to/large-file.txt')
if (stat.size > 100 * 1024 * 1024) {
  // 100MB
  console.log('Large file detected, consider streaming')
}

Directory Navigation

// List all files in documents directory
const files = await NitroFS.readdir(NitroFS.DOCUMENT_DIR)

// Filter for specific file types
const textFiles = files.filter((file) => file.endsWith('.txt'))

// Get file stats for each file
for (const file of files) {
  const filePath = `${NitroFS.DOCUMENT_DIR}/${file}`
  const stat = await NitroFS.stat(filePath)
  console.log(`${file}: ${stat.size} bytes`)
}

File Backup Example

const backupFile = async (sourcePath: string) => {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
  const backupPath = `${NitroFS.DOCUMENT_DIR}/backup-${timestamp}.txt`

  try {
    await NitroFS.copyFile(sourcePath, backupPath)
    console.log('Backup created successfully')
  } catch (error) {
    console.error('Backup failed:', error.message)
  }
}

🚨 Common Issues & Solutions

Permission Errors

Issue: "Permission denied" errors on Android Solution: Ensure your app has the necessary permissions in AndroidManifest.xml:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Large File Handling

Issue: Memory issues with large files Solution: The library automatically handles large files with chunked reading, but you can implement custom streaming for very large files.

Network Timeouts

Issue: Upload/download operations hanging Solution: The library includes timeout handling, but you can implement custom timeout logic:

const uploadWithTimeout = async (
  file: NitroFile,
  options: NitroUploadOptions
) => {
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Upload timeout')), 30000)
  })

  return Promise.race([NitroFS.uploadFile(file, options), timeoutPromise])
}

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/patrickkabwe/react-native-nitro-fs.git
cd react-native-nitro-fs

# Install dependencies
bun install

# Run example app
cd example
bun install
npx react-native run-ios  # or run-android

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Credits

Bootstrapped with create-nitro-module.


Made with ❀️ for the React Native community

About

A high-performance file system module for React Native that handles file operations and transfers with native speed.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •