Downloading Files
Download files from the remote server to your local device:Copy
Ask AI
const downloadedPath = await client.sftpDownload(
'/remote/path/to/file.txt',
'/local/path/to/save/'
);
console.log('File downloaded to:', downloadedPath);
Basic Download Example
- Async/Await
- Callback
Copy
Ask AI
import SSHClient from '@dylankenneally/react-native-ssh-sftp';
import RNFS from 'react-native-fs';
const downloadFile = async () => {
try {
const client = await SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
);
const localPath = RNFS.DocumentDirectoryPath;
const downloadedFile = await client.sftpDownload(
'/home/user/document.pdf',
localPath
);
console.log('Downloaded to:', downloadedFile);
client.disconnect();
} catch (error) {
console.error('Download failed:', error);
}
};
Copy
Ask AI
import SSHClient from '@dylankenneally/react-native-ssh-sftp';
import RNFS from 'react-native-fs';
SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
).then(client => {
const localPath = RNFS.DocumentDirectoryPath;
client.sftpDownload(
'/home/user/document.pdf',
localPath,
(error, downloadedFile) => {
if (error) {
console.error('Download failed:', error);
} else {
console.log('Downloaded to:', downloadedFile);
}
client.disconnect();
}
);
});
Uploading Files
Upload files from your local device to the remote server:Copy
Ask AI
await client.sftpUpload(
'/local/path/to/file.txt',
'/remote/path/to/destination/'
);
console.log('File uploaded successfully');
Basic Upload Example
Copy
Ask AI
import SSHClient from '@dylankenneally/react-native-ssh-sftp';
import RNFS from 'react-native-fs';
const uploadFile = async () => {
try {
const client = await SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
);
const localFile = `${RNFS.DocumentDirectoryPath}/photo.jpg`;
const remotePath = '/home/user/uploads/';
await client.sftpUpload(localFile, remotePath);
console.log('Upload complete');
client.disconnect();
} catch (error) {
console.error('Upload failed:', error);
}
};
Progress Tracking
Monitor upload and download progress in real-time using event listeners.Download Progress
Register the progress handler
Set up the
DownloadProgress event listener before starting the download:Copy
Ask AI
client.on('DownloadProgress', (event) => {
console.log('Download progress:', event);
});
Upload Progress
Register the progress handler
Set up the
UploadProgress event listener before starting the upload:Copy
Ask AI
client.on('UploadProgress', (event) => {
console.log('Upload progress:', event);
});
Complete Progress Example
- Download with UI
- Upload with UI
- Both with Stats
Copy
Ask AI
import React, { useState } from 'react';
import { View, Text, Button, ProgressBarAndroid } from 'react-native';
import SSHClient from '@dylankenneally/react-native-ssh-sftp';
import RNFS from 'react-native-fs';
const FileDownloader = () => {
const [progress, setProgress] = useState(0);
const [downloading, setDownloading] = useState(false);
const downloadFile = async () => {
try {
setDownloading(true);
const client = await SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
);
// Track progress
client.on('DownloadProgress', (event) => {
if (event && event.progress !== undefined) {
setProgress(event.progress);
}
});
await client.sftpDownload(
'/remote/large-file.zip',
RNFS.DocumentDirectoryPath
);
setProgress(100);
console.log('Download complete!');
client.disconnect();
} catch (error) {
console.error('Download error:', error);
} finally {
setDownloading(false);
}
};
return (
<View>
<Button
title="Download File"
onPress={downloadFile}
disabled={downloading}
/>
{downloading && (
<>
<ProgressBarAndroid
styleAttr="Horizontal"
progress={progress / 100}
/>
<Text>{progress.toFixed(1)}%</Text>
</>
)}
</View>
);
};
Copy
Ask AI
import React, { useState } from 'react';
import { View, Text, Button, ProgressBarAndroid } from 'react-native';
import SSHClient from '@dylankenneally/react-native-ssh-sftp';
import RNFS from 'react-native-fs';
const FileUploader = () => {
const [progress, setProgress] = useState(0);
const [uploading, setUploading] = useState(false);
const uploadFile = async () => {
try {
setUploading(true);
const client = await SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
);
// Track progress
client.on('UploadProgress', (event) => {
if (event && event.progress !== undefined) {
setProgress(event.progress);
}
});
await client.sftpUpload(
`${RNFS.DocumentDirectoryPath}/large-file.zip`,
'/remote/uploads/'
);
setProgress(100);
console.log('Upload complete!');
client.disconnect();
} catch (error) {
console.error('Upload error:', error);
} finally {
setUploading(false);
}
};
return (
<View>
<Button
title="Upload File"
onPress={uploadFile}
disabled={uploading}
/>
{uploading && (
<>
<ProgressBarAndroid
styleAttr="Horizontal"
progress={progress / 100}
/>
<Text>{progress.toFixed(1)}%</Text>
</>
)}
</View>
);
};
Copy
Ask AI
const [stats, setStats] = useState({
bytesTransferred: 0,
totalBytes: 0,
percentage: 0,
speed: 0 // bytes per second
});
let lastUpdate = Date.now();
let lastBytes = 0;
client.on('DownloadProgress', (event) => {
const now = Date.now();
const timeDiff = (now - lastUpdate) / 1000; // seconds
const bytesDiff = event.bytesTransferred - lastBytes;
const speed = timeDiff > 0 ? bytesDiff / timeDiff : 0;
setStats({
bytesTransferred: event.bytesTransferred,
totalBytes: event.totalBytes,
percentage: (event.bytesTransferred / event.totalBytes) * 100,
speed: speed
});
lastUpdate = now;
lastBytes = event.bytesTransferred;
});
// Display helper functions
const formatBytes = (bytes) => {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
};
// In your JSX:
<Text>
{formatBytes(stats.bytesTransferred)} / {formatBytes(stats.totalBytes)}
({stats.percentage.toFixed(1)}%)
</Text>
<Text>Speed: {formatBytes(stats.speed)}/s</Text>
Progress event handlers must be registered before initiating the transfer. The SFTP connection automatically registers progress listeners when established.
Canceling Transfers
You can cancel ongoing uploads and downloads at any time.Cancel Download
Copy
Ask AI
client.sftpCancelDownload();
Cancel Upload
Copy
Ask AI
client.sftpCancelUpload();
Complete Cancellation Example
Copy
Ask AI
import React, { useState, useRef } from 'react';
import { View, Button, Text } from 'react-native';
import SSHClient from '@dylankenneally/react-native-ssh-sftp';
import RNFS from 'react-native-fs';
const FileTransferWithCancel = () => {
const [progress, setProgress] = useState(0);
const [transferring, setTransferring] = useState(false);
const clientRef = useRef(null);
const startDownload = async () => {
try {
setTransferring(true);
setProgress(0);
const client = await SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
);
clientRef.current = client;
client.on('DownloadProgress', (event) => {
if (event && event.progress !== undefined) {
setProgress(event.progress);
}
});
await client.sftpDownload(
'/remote/large-file.zip',
RNFS.DocumentDirectoryPath
);
console.log('Download complete!');
} catch (error) {
if (error.message.includes('cancel')) {
console.log('Download cancelled by user');
} else {
console.error('Download error:', error);
}
} finally {
setTransferring(false);
if (clientRef.current) {
clientRef.current.disconnect();
clientRef.current = null;
}
}
};
const cancelDownload = () => {
if (clientRef.current && transferring) {
clientRef.current.sftpCancelDownload();
console.log('Cancelling download...');
}
};
return (
<View>
<Button
title="Start Download"
onPress={startDownload}
disabled={transferring}
/>
<Button
title="Cancel Download"
onPress={cancelDownload}
disabled={!transferring}
/>
{transferring && <Text>Progress: {progress.toFixed(1)}%</Text>}
</View>
);
};
- Canceling a transfer will reject the promise with an error
- Partially transferred files may remain on the filesystem
- Always handle the cancellation error appropriately in your code
Working with Different File Types
Text Files
Copy
Ask AI
import RNFS from 'react-native-fs';
// Download
const filePath = await client.sftpDownload(
'/remote/config.json',
RNFS.DocumentDirectoryPath
);
// Read the content
const content = await RNFS.readFile(filePath, 'utf8');
const config = JSON.parse(content);
Binary Files (Images, Videos, etc.)
Copy
Ask AI
import RNFS from 'react-native-fs';
import { Image } from 'react-native';
// Download image
const imagePath = await client.sftpDownload(
'/remote/photos/image.jpg',
RNFS.DocumentDirectoryPath
);
// Use in Image component
<Image source={{ uri: `file://${imagePath}` }} />
Large Files
For large files, always implement:
- Progress tracking to show transfer status
- Cancellation capability for user control
- Error handling for network interruptions
- Retry logic for failed transfers
Copy
Ask AI
const downloadLargeFile = async (client, remotePath, localPath) => {
let retries = 3;
while (retries > 0) {
try {
await client.sftpDownload(remotePath, localPath);
console.log('Download successful');
return;
} catch (error) {
retries--;
if (retries === 0) {
throw error;
}
console.log(`Download failed, retrying... (${retries} attempts left)`);
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
};
Batch Transfers
Transfer multiple files sequentially or in parallel:Sequential Transfers
Sequential Transfers
Copy
Ask AI
const filesToDownload = [
'/remote/file1.txt',
'/remote/file2.txt',
'/remote/file3.txt'
];
for (const remoteFile of filesToDownload) {
try {
await client.sftpDownload(
remoteFile,
RNFS.DocumentDirectoryPath
);
console.log(`Downloaded: ${remoteFile}`);
} catch (error) {
console.error(`Failed to download ${remoteFile}:`, error);
}
}
Parallel Transfers (Multiple Clients)
Parallel Transfers (Multiple Clients)
Copy
Ask AI
const downloadFiles = async (files) => {
const downloads = files.map(async (file) => {
const client = await SSHClient.connectWithPassword(
'10.0.0.10',
22,
'user',
'password'
);
try {
await client.sftpDownload(file, RNFS.DocumentDirectoryPath);
console.log(`Downloaded: ${file}`);
} finally {
client.disconnect();
}
});
await Promise.all(downloads);
};
const files = [
'/remote/file1.txt',
'/remote/file2.txt',
'/remote/file3.txt'
];
await downloadFiles(files);
Best Practices
Always use absolute paths
Copy
Ask AI
// Good
await client.sftpDownload(
'/home/user/file.txt',
RNFS.DocumentDirectoryPath
);
// Avoid relative paths
await client.sftpDownload(
'file.txt', // Where is this?
RNFS.DocumentDirectoryPath
);
Check available storage space
Copy
Ask AI
import RNFS from 'react-native-fs';
const freeSpace = await RNFS.getFSInfo();
const fileInfo = await client.sftpLs('/remote');
const targetFile = fileInfo.find(f => f.filename === 'large-file.zip');
if (targetFile.fileSize > freeSpace.freeSpace) {
console.error('Insufficient storage space');
return;
}
await client.sftpDownload('/remote/large-file.zip', RNFS.DocumentDirectoryPath);
Handle network interruptions
Copy
Ask AI
const downloadWithRetry = async (remotePath, localPath, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
return await client.sftpDownload(remotePath, localPath);
} catch (error) {
if (i === maxRetries - 1) throw error;
console.log(`Retry ${i + 1}/${maxRetries}`);
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
};
Clean up partial transfers
Copy
Ask AI
const downloadPath = `${RNFS.DocumentDirectoryPath}/download.zip`;
try {
await client.sftpDownload('/remote/file.zip', RNFS.DocumentDirectoryPath);
} catch (error) {
// Remove partial download
if (await RNFS.exists(downloadPath)) {
await RNFS.unlink(downloadPath);
}
throw error;
}
Next Steps
- Learn about SFTP operations for directory management
- Explore SSH command execution for remote operations
- Check platform-specific considerations for iOS and Android differences