An Elixir SFTP Client that wraps Erlang's ssh and ssh_sftp.
- Erlang 24 or greater
- Elixir 1.11 or greater
The package can be installed by adding :sftp_client
to your list of
dependencies in mix.exs
:
def deps do
[
{:sftp_client, "~> 2.1"}
]
end
There are bang (!) counterparts for almost all available functions.
To open a new connection to an SFTP server:
{:ok, conn} = SFTPClient.connect(host: "ftp.myhost.com")
Due to a change in OTP
24
that removed automatic public key lookup in the sftp module you may need to
define the modify_algorithms
option to avoid "Key exchange failed" errors:
{:ok, conn} = SFTPClient.connect(
host: "ftp.myhost.com",
modify_algorithms: [
append: [
public_key: [:"ssh-rsa"]
]
]
)
Refer to the docs for SFTPClient.Operations.Connect.connect/1
to find out
all available options.
It is strongly recommended to close a connection after your operations have completed:
SFTPClient.disconnect(conn)
For short-lived connections you can also use a function as second argument. After the function body has run or raises, the connection is automatically closed.
SFTPClient.connect([host: "ftp.myhost.com"], fn conn ->
# Do something with conn
end)
To download a file from the server you can use the following function.
SFTPClient.download_file(conn, "my/remote/dir/file.jpg", "my/dir/local-file.jpg")
# => {:ok, "my/dir/local-file.jpg"}
When the third argument is an existing directory on your file system, the file is downloaded to a file with the same name as the one on the server.
SFTPClient.download_file(conn, "my/remote/dir/image.png", "my/local/dir")
# => {:ok, "my/local/dir/image.png"}
It is also possible to use Streams to download data into a file or memory.
source_stream = SFTPClient.stream_file!(conn, "my/remote/file.jpg")
target_stream = File.stream!("my/local/file.jpg")
source_stream
|> Stream.into(target_stream)
|> Stream.run()
To upload are file from the file system you can use the following function.
SFTPClient.upload_file(conn, "my/local/dir/file.jpg", "my/remote/dir/file.jpg")
# => {:ok, "my/remote/dir/file.jpg"}
You can also use Streams to upload data. Please make sure to set a proper chunk size or the upload may be very slow.
source_stream = File.stream!("my/local/file.jpg", [], 32_768)
target_stream = SFTPClient.stream_file!(conn, "my/remote/file.jpg")
source_stream
|> Stream.into(target_stream)
|> Stream.run()
SFTPClient.list_dir(conn, "my/dir")
# => {:ok, ["my/dir/file_1.jpg", "my/dir/file_2.jpg", ...]}
SFTPClient.make_dir(conn, "my/new/dir")
Note that this operation fails unless the parent directory exists.
To delete a file:
SFTPClient.delete_file(conn, "my/remote/file.jpg")
To delete a directory:
SFTPClient.delete_dir(conn, "my/remote/dir")
Note that a directory cannot be deleted as long as it still contains files.
To move/rename a file or directory:
SFTPClient.rename(conn, "my/remote/file.jpg", "my/remote/new-file.jpg")
You can retrieve meta data about a file from the server such as file size, modification time, file permissions, owner and so on.
SFTPClient.file_info(conn, "my/remote/file.jpg")
# => {:ok, %File.Stat{...}}
Refer to the File.Stat
docs for a
list of available file information.
There are also a couple of functions that handle symlinks.
It is possible to get the target of a symlink.
SFTPClient.read_link(conn, "my/remote/link.jpg")
# => {:ok, "my/remote/file.jpg"}
You can retrieve meta data about symlinks, similar to file_info/2
.
SFTPClient.link_info(conn, "my/remote/link.jpg")
# => {:ok, %File.Stat{...}}
And you are able to create symlinks.
SFTPClient.make_link(conn, "my/remote/link.jpg", "my/remote/file.jpg")
This library is released under the MIT License. See the LICENSE.md file for further details.