| Type: | Package |
| Title: | Robust SFTP Interface Using 'curl' |
| Version: | 0.2.0 |
| Description: | Provides a high-level, object-oriented interface for Secure File Transfer Protocol (SFTP) operations built upon the 'curl' package. The package implements an 'R6' class to manage persistent connections and provides 'tidyverse'-style functions for common file system tasks. Key features include recursive directory creation with idempotency support, "smart" local path resolution that distinguishes between files and directories, and the ability to download remote resources directly into memory as raw vectors for seamless integration into data processing pipelines. It is designed to handle common SFTP edge cases gracefully, providing informative error messages and robust path sanitization to ensure compatibility across different server configurations. |
| License: | MIT + file LICENSE |
| URL: | https://mikuo0628.github.io/sftpR/, https://github.com/mikuo0628/sftpR |
| BugReports: | https://github.com/mikuo0628/sftpR/issues |
| Encoding: | UTF-8 |
| SystemRequirements: | libcurl: libcurl (with libssh2 support) |
| Depends: | R (≥ 4.1.0) |
| Imports: | curl (≥ 7.0.0), R6 (≥ 2.6.1) |
| RoxygenNote: | 7.3.3 |
| Suggests: | knitr, rmarkdown, testthat (≥ 3.0.0), withr |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| Collate: | 'sftp_connect.R' 'sftp_delete.R' 'sftp_download.R' 'sftp_list.R' 'sftp_mkdir.R' 'sftp_rename.R' 'sftp_upload.R' 'utils.R' 'shared_docs.R' |
| NeedsCompilation: | no |
| Packaged: | 2026-04-03 17:10:35 UTC; rstudio |
| Author: | Michael Kuo [aut, cre] |
| Maintainer: | Michael Kuo <michael.kuo@bccdc.ca> |
| Repository: | CRAN |
| Date/Publication: | 2026-04-09 15:40:02 UTC |
Build SFTP URL components
Description
Helper (stateless) function to construct a full SFTP URL and its components from the given protocol, hostname, port, and path Hostname will be sanitized for minor formatting issues; if a port or path are found inside 'hostname' they will override the corresponding arguments.
Usage
.build_sftp_url(
protocol = "sftp",
user = NULL,
hostname = NULL,
port = "22",
path = NULL,
.verbose = TRUE
)
Arguments
protocol |
Character. Protocol string. Defaults to "sftp". |
user |
Character. SFTP account name. |
hostname |
Character. Server URL or IP. Defaults to "localhost". |
port |
Character. Port number. Defaults to "22". |
path |
Character. Sub-path on server. |
.verbose |
Logical. Defaults to |
Value
A list with components: full_url, protocol, hostname, port, path.
Parse and Validate SFTP URL Components
Description
Internal utility to deconstruct an SFTP URL into its constituent parts (protocol, user, hostname, port, and path). It enforces security by disallowing absolute paths (indicated by double slashes) and performs basic sanitization.
Usage
.parse_sftp_url(url, .verbose = TRUE)
Arguments
url |
A character string containing the SFTP URL. |
.verbose |
Logical. Defaults to |
Details
The function uses a single-pass regular expression to extract components. It specifically blocks "Root Access" attempts (e.g., 'sftp://host//etc') by checking if the captured path starts with a forward slash.
Value
A named list containing:
protocol |
The scheme (e.g., "sftp"). |
user |
The username if provided (e.g., "john"). |
hostname |
The server address (IPv4, IPv6, or domain). |
port |
The port number as a string. |
path |
The file or directory path relative to the home directory. |
Parse SFTP Directory Listings into Data Frames
Description
A utility function that converts the raw binary content of an SFTP directory
listing (returned by curl) into a structured R data.frame.
Usage
.sftp_parse(resp = NULL, sftp_url = NULL, h = NULL)
Arguments
resp |
A response list from |
sftp_url |
Character. The SFTP URL to fetch if |
h |
A |
Details
The function automatically filters out the special Unix directory entries
"." and "..". It determines object types based on the first
character of the permission string (e.g., 'd' for directory).
Value
A data.frame with parsed Unix-style directory metadata,
or NULL if the directory is empty.
Validate and Sanitize SFTP URLs against a Connection Object
Description
This internal utility ensures that a user-provided URL matches the
"Source of Truth" defined in an SFTPConn object.
It prevents common formatting errors, warns against security-risky
root access attempts (double slashes), and corrects any incongruities
in the protocol, hostname, or port.
Usage
.validate_sftp_url(sftp_conn, user_url, .verbose = sftp_conn$.verbose)
Arguments
sftp_conn |
An |
user_url |
Character string. The destination SFTP URL or path provided by the user. |
.verbose |
Logical. Defaults to |
Details
The function performs the following steps:
Checks for empty inputs.
Detects and "heals" double-slash root access attempts (e.g., 'sftp://host//path' becomes 'sftp://host/path').
Deconstructs the URL using regular expressions to compare its components against the 'sftp_conn' settings.
Issues a warning if the user-provided protocol, hostname, or port differs from the established connection.
Reconstructs a clean, standardized URL.
Value
A sanitized character string containing the validated SFTP URL.
SFTP Connection Class
Description
An R6 class to safely store information needed for SFTP connection,
with convenient methods to check connections and existence of files or
directories, and create specific handles for sftp_* function family of
CRUD operations.
Details
One important goal of this design choice is to keep user credentials
safe, as private fields. Credentails are used to create specific handles
for sftp_* family, and are reused where approrpiate. SFTPConn
This class checks if credential is valid, and has a internal convenience
methods such as safe printing for basic information, checking destination
existence, and ensuring URL is correctly formatted.
Value
SFTPConn R6 class object, used in sftp_* family.
Public fields
protocolThe connection protocol.
hostnameThe server address or IP.
pathThe target subdirectory on the server.
portThe port number.
timeoutConnection timeout in seconds.
hThe internal curl handle used for connection checks, listing directories, and download files.
.verboseLogical; if TRUE, prints detailed curl output.
last_errorCharacter string of the last connection error.
Active bindings
clean_urlReturns the processed SFTP URL via internal
.build_sftp_url.
Methods
Public methods
Method new()
Initialize 'SFTPConn' class R6 object.
Usage
sftp_conn_generator$new( protocol = "sftp", hostname = "localhost", path = NULL, port = "22", user = NA_character_, password = NA_character_, timeout = 30L, ..., .verbose = TRUE )
Arguments
protocolCharacter. Protocol string. Defaults to "sftp".
hostnameCharacter. Server URL or IP. Defaults to "localhost".
pathCharacter. Sub-path on server.
portCharacter. Port number. Defaults to "22".
userCharacter. SFTP account name.
passwordCharacter. SFTP password.
timeoutInteger. Connection timeout.
...Additional arguments passed to
curl::handle_setopt()..verboseLogical. Defaults to
TRUE. Prints helpful messages.
Returns
An 'SFTPConn' object with safely stored user credential and convenience methods for various operations, such as checking connection and existence, and creating handles for CRUD operations.
Method connection_ok()
Checks if the current connection settings and credentials are valid.
Usage
sftp_conn_generator$connection_ok()
Returns
Logical; TRUE if connection is successful.
Method print()
Custom print method to display connection status without exposing passwords.
Usage
sftp_conn_generator$print(...)
Arguments
...Unused.
Method .upload_handle()
Internal method to generate a specialized upload handle with streaming.
Adapted from curl::curl_upload().
Usage
sftp_conn_generator$.upload_handle( local_file, reuse = TRUE, .verbose = self$.verbose, ... )
Arguments
local_filePath to file, data.frame, or connection.
reuseLogical; try to keep connection alive.
.verboseLogical. Defaults to
TRUE. Prints helpful messages....Additional options for
curl::handle_setopt().
Method .quote_handle()
Createshandle that uses 'quote' option. Specifically for deleting, creating directories, and renaming files or directories.
Usage
sftp_conn_generator$.quote_handle(
remote_url_from = NULL,
remote_url_to = NULL,
purpose = c("rm", "mkdir", "rename"),
.verbose = self$.verbose,
.ignore_error = FALSE,
...
)Arguments
remote_url_fromCharacter. The URL to delete, to create, or to rename from.
remote_url_toCharacter. The URL to rename to. Ignored for delete or directory create operations.
purposeCharacter. Choose one of 3 options:
"rm": to delete file or directory.
"mkdir": to create directory. Path should be a directory.
"rename": to rename
.verboseLogical. Defaults to
TRUE. Prints helpful messages..ignore_errorLogical. Defaults to 'FALSE'. If
TRUE, error will not interrupt subsequent execution. See 'Details'....Options that for
curl::handle_setopt().
Details
In 'curl', adding an asterisk ('*') at the very beginning of a command (ie. one of the 3 used in 'purpose' argument) acts as a "fail-safe" or "ignore-error" prefix. It silently ignores any failure returned by the command, and continues without being interrupted by the error. Check if a remote path exists
Method .exists()
An internal helper that pings the SFTP/FTP server to verify the existence of a file or directory.
Usage
sftp_conn_generator$.exists(sftp_url = NULL)
Arguments
sftp_urlCharacter. The full URL to the remote resource. If
NULL, returnsFALSE.
Details
This method uses CURLOPT_NOBODY = TRUE to perform a
protocol-level STAT request. This is highly efficient
as it retrieves only metadata and does not attempt to download or
list contents.
Because STAT is slash-agnostic in the SFTP protocol, this check
will return TRUE for a directory regardless of whether a trailing
forward-slash is provided in the URL.
However, this is the only operation where URL is "safe" from the consequences of un-normalized URLs. Be wary of incorrect multiple slash placements as they will be collapsed into one slash and won't throw errors.
Returns
Logical. TRUE if the resource exists and is accessible;
FALSE otherwise.
URL "fixing" via range probing
Method .fix_url_type()
An internal diagnostic method that determines if a remote URL requires a trailing slash by attempting to read a single byte (Range: 0-0).
Usage
sftp_conn_generator$.fix_url_type(remote_url)
Arguments
remote_urlCharacter. The full SFTP/FTP URL to validate.
Details
This method leverages a protocol behavior:
-
Files allow byte-range requests; the probe succeeds.
-
Directories reject byte-range requests; the probe fails.
If the initial probe fails, the method "flips" the trailing slash (adds one if missing, or removes one if present) and returns the modified URL. This addresses the common 'libcurl' issue where directory listings fail without an explicit trailing slash.
Returns
A character string containing the "fixed" URL. Note that if the path truly does not exist, the flipped URL is still returned; the final operation (upload/list) will handle the ultimate failure.
Method clone()
The objects of this class are cloneable with this method.
Usage
sftp_conn_generator$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Note
This method uses a 5-second connecttimeout to ensure
the probe doesn't hang on unresponsive servers.
Create an SFTPConn R6 object that contains important connection
information safely
Description
An R6 class to safely store information needed for SFTP connection,
with convenient methods to check connections and existence of files or
directories, and create specific handles for sftp_* function family of
CRUD operations.
Usage
sftp_connect(
protocol = "sftp",
hostname = "localhost",
path = NULL,
port = "22",
user = NA_character_,
password = NA_character_,
timeout = 30L,
...,
.verbose = TRUE
)
Arguments
protocol |
Character. Protocol string. Defaults to "sftp". |
hostname |
Character. Server URL or IP. Defaults to "localhost". |
path |
Character. Sub-path on server. |
port |
Character. Port number. Defaults to "22". |
user |
Character. SFTP account name. |
password |
Character. SFTP password. |
timeout |
Integer. Connection timeout. |
... |
Additional arguments passed to |
.verbose |
Logical. Defaults to |
Details
One important goal of this design choice is to keep user credentials
safe, as private fields. Credentails are used to create specific handles
for sftp_* family, and are reused where approrpiate. SFTPConn
This class checks if credential is valid, and has a internal convenience
methods such as safe printing for basic information, checking destination
existence, and ensuring URL is correctly formatted.
Value
SFTPConn R6 class object, used in sftp_* family.
Examples
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create a new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = 2222,
user = "tester",
password = "password123"
)
}
Delete Files or Directories from SFTP Server
Description
Deletes a specific file or directory from the remote server. If the target
is a directory, it must be empty unless .recursive = TRUE
is specified.
Usage
sftp_delete(
sftp_conn,
remote_url = NULL,
.recursive = FALSE,
.verbose = TRUE,
.validate = TRUE
)
Arguments
sftp_conn |
An |
remote_url |
Character. The full URL or path of the file or directory to be operated on. |
.recursive |
Logical. Defaults to
|
.verbose |
Logical. Defaults to |
.validate |
Logical. Whether to validate the |
Value
TRUE (invisibly) if the operation was successful.
Safety Warnings
-
Irreversibility: Deletion on SFTP is permanent. There is no "Trash" or "Recycle Bin" on most SFTP server configurations.
-
Recursive Caution: Setting
.recursive = TRUEon a high-level directory can result in significant data loss. Always verify theremote_urlbefore executing.
Examples
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = "2222",
user = "tester",
password = "password123"
)
# Delete a single file
sftp_delete(sftp_conn, "project/old_report.csv")
# Delete an entire directory and its contents
sftp_delete(sftp_conn, "project/temp_outputs/", .recursive = TRUE)
}
Download Files from SFTP Server
Description
Downloads a file from a remote SFTP server to a local disk location or directly into R's memory as a raw vector.
Usage
sftp_download(
sftp_conn,
remote_file,
local_file = NA_character_,
.create_dir = FALSE,
.overwrite = FALSE,
.verbose = TRUE,
...
)
Arguments
sftp_conn |
An |
remote_file |
Character. The path or URL of the file on the SFTP server. |
local_file |
Character or
|
.create_dir |
Logical. Defaults to |
.overwrite |
Logical. Defaults to |
.verbose |
Logical. Defaults to |
... |
Additional arguments passed to |
Value
If local_file is NULL, a raw vector of the file
contents. Otherwise, the resolved local path to the saved file (invisibly).
Local Path Resolution Caveats
To provide a "smart" user experience, the function guesses
if local_file is intended to be a directory or a specific filename:
-
Directory Detection: If the path exists as a directory, ends in a trailing slash, or has no file extension, it is treated as a folder. The
remote_filefilename will be appended to this path. -
File Detection: If the path does not exist and contains a file extension (e.g., ".csv"), it is treated as the final destination filename.
-
Ambiguity: In ambiguous cases (e.g., a non-existent path without a slash or extension), the function defaults to treating the path as a directory.
Examples
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = "2222",
user = "tester",
password = "password123"
)
# Download and use the remote filename
sftp_download(sftp_conn, "data/raw_logs.zip")
# Download to a specific local name
sftp_download(sftp_conn, "remote_file.csv", "local_name.csv")
# Download to memory for immediate processing
raw_bytes <- sftp_download(sftp_conn, "data.json", local_file = NULL)
# Parse with appropriate packages
# data <- jsonlite::fromJSON(rawToChar(raw_bytes))
}
List and Crawl SFTP Directory Contents
Description
Retrieves a directory listing from an SFTP server. If
.recursive = TRUE, it will perform a depth-first crawl of all
subdirectories found, implementing a path-tracking
algorithm to detect and skip circular symbolic links, preventing
infinite recursion and stack overflow errors.
Usage
sftp_list(
sftp_conn = NULL,
sftp_url = NULL,
.verbose = TRUE,
.recursive = FALSE
)
Arguments
sftp_conn |
An |
sftp_url |
A SFTP URL of which the contents will be listed. If
|
.verbose |
Logical. Defaults to |
.recursive |
Logical. Defaults to
|
Value
A data.frame containing remote file/directory metadata:
-
permission: Unix-style permission string (e.g., "drwxr-xr-x"). -
nlink: Number of hard links. -
user: Owner username. -
group: Owner group. -
size: File size in bytes. -
month, day, time_year: Timestamp components. -
name: File or directory name. -
type: Categorization as "dir" or "file". -
url: The source URL for that specific object.
Examples
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create a new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = "2222",
user = "tester",
password = "password123"
)
# List recursively
sftp_list(sftp_conn, .recursive = TRUE)
}
Create Remote Directories in SFTP
Description
This function creates directories on a remote server using the SFTP protocol.
It supports recursive directory creation, effectively behaving like
mkdir -p on a Unix-like system.
Usage
sftp_mkdir(
sftp_conn,
remote_url = NULL,
.recursive = TRUE,
.verbose = TRUE,
.ignore_error = .recursive
)
Arguments
sftp_conn |
An |
remote_url |
Character. The full URL or path of the file or directory to be operated on. |
.recursive |
Logical. Defaults to
|
.verbose |
Logical. Defaults to |
.ignore_error |
Logical. If |
Details
When .recursive = TRUE, the function splits the path into segments and
attempts to create each one sequentially. It uses the * prefix for
internal calls to ensure that existing directories do not trigger errors.
Value
invisible(TRUE) on success.
Examples
## Not run:
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = "2222",
user = "tester",
password = "password123"
)
# Create a nested directory structure
sftp_mkdir(sftp_conn, "project/data/results/2026", .recursive = TRUE)
# Create a single directory and fail if parents are missing
sftp_mkdir(sftp_conn, "simple_dir", .recursive = FALSE)
}
## End(Not run)
Rename or Move Remote SFTP Resources
Description
Renames a file or directory on the SFTP server. This can also be used to move files between directories.
Usage
sftp_rename(
sftp_conn,
remote_url_from = NULL,
remote_url_to = NULL,
.recursive = FALSE,
.verbose = TRUE
)
Arguments
sftp_conn |
An |
remote_url_from |
Character. The current path of the file or directory. |
remote_url_to |
Character. The new path for the file or directory. |
.recursive |
Logical. Defaults to
|
.verbose |
Logical. Defaults to |
Details
The SFTP protocol's rename command is typically non-overwriting. If
remote_url_to already exists, the operation will fail.
When .recursive = TRUE, parent directories of remote_url_to
are identified, and existence ensured before attempting the renaming.
Value
invisible(TRUE) on success.
Examples
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = "2222",
user = "tester",
password = "password123"
)
# Simple rename in the same folder
sftp_rename(sftp_conn, "old_name.csv", "new_name.csv")
# Move a file to a new, potentially non-existent directory
sftp_rename(
sftp_conn,
"data/raw.csv",
"archive/2026/processed.csv",
.recursive = TRUE
)
}
Upload a file to an SFTP server
Description
A robust wrapper to upload local files or data frames to a remote SFTP server. It manages the libcurl handle lifecycle, ensures connections are closed, and validates URLs against the connection's "Source of Truth".
Usage
sftp_upload(
sftp_conn,
local_file,
remote_file = NULL,
.create_dir = FALSE,
.verbose = TRUE
)
Arguments
sftp_conn |
An |
local_file |
Character string (path to a file) or a |
remote_file |
Character string. The destination path on the server.
If |
.create_dir |
Logical. Defaults to |
.verbose |
Logical. Defaults to |
Details
The function uses a secure lifecycle:
Validates the remote URL to prevent credential leakage.
Opens a file connection to the local source.
Uses
on.exitto ensure file handles are released and temporary files are unlinked even if the transfer is interrupted.
Value
Returns TRUE (invisibly) on success. Throws an error on failure.
Examples
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
# Create new SFTP connection
sftp_conn <- sftp_connect(
hostname = "127.0.0.1",
port = "2222",
user = "tester",
password = "password123"
)
# Upload `my_df` as csv
sftp_upload(conn, my_df, "uploads/data.csv")
}
Shared Parameter Documentation
Description
Shared Parameter Documentation
Arguments
protocol |
Character. Protocol string. Defaults to "sftp". |
hostname |
Character. Server URL or IP. Defaults to "localhost". |
path |
Character. Sub-path on server. |
port |
Character. Port number. Defaults to "22". |
user |
Character. SFTP account name. |
password |
Character. SFTP password. |
timeout |
Integer. Connection timeout. |
... |
Additional arguments passed to |
.verbose |
Logical. Defaults to |
sftp_conn |
An |
remote_url |
Character. The full URL or path of the file or directory to be operated on. |
.recursive |
Logical. Defaults to
|
.create_dir |
Logical. Defaults to |