Net::SFTP FAQ

What is Net::SFTP?

Net::SFTP is a pure-Ruby implementation of the SFTP protocol. That’s “SFTP” as in “Secure File Transfer Protocol”, as defined as an adjuct to the SSH specification. Not “SFTP” as in “Secure FTP” (a completely different beast). Nor is it an implementation of the “Simple File Transfer Protocol” (which is in no way secure).

How do I… ...connect to an SFTP server? I’d like to connect without first getting a Net::SSH connection…

Something like this:

  require 'net/sftp'

  Net::SFTP.start(host, user, password) do |sftp|
    ...
  end

Net::SFTP.start accepts the same parameters as Net::SSH.start, so I’ll direct you to that documentation for all the particulars.

How do I… ...connect to an SFTP server? I already have an open Net::SSH connection…

You can piggy-back an SFTP connection on an existing Net::SSH connection, which can be useful if you’ve already got an SSH connection that you’re using for port forwarding or whatever.

  require 'net/ssh'
  require 'net/sftp'

  Net::SSH.start(host, user, password) do |ssh|
    ...
    ssh.sftp.connect do |sftp|
      ...
    end
    ...
  end
How do I… ...upload data? I want to upload an entire file on disk…

Assuming you already have an SFTP connection:

  sftp.put_file "/path/to/local.file", "/path/to/remote.file" 
How do I… ...upload data? I want to upload bytes from a string or other object…

Assuming you already have an SFTP connection, and your data is stored in a string named data:

  sftp.open_handle("/path/to/remote.file", "w") do |handle|
    result = sftp.write(handle, data)
    puts result.code # the result of the operation
  end

If (for whatever reason) you’d rather not use blocks, you can do without, but be sure to call close_handle when you’re done:

  handle = sftp.open_handle("/path/to/remote.file", "w")
  result = sftp.write(handle, data)
  puts result.code # the result of the operation
  sftp.close_handle(handle)
How do I… ...download data? I want to download directly to a local file…

Assuming you already have an SFTP connection:

  sftp.get_file "/path/to/remote.file", "/path/to/local.file" 
How do I… ...download data? I want to download to a string in memory…

Assuming you already have an SFTP connection:

  data = nil
  sftp.open_handle("/path/to/remote.file") do |handle|
    data = sftp.read(handle)
  end
How do I… ...download data? I want to be notified of the progress of the download…

You can specify both a “chunk size” and a “progress callback”. The callback will be invoked for every “chunk size” bytes that are received:

  sftp.open_handle("/path/to/remote.file") do |handle|
    begin
      STDOUT.sync = true
      data = sftp.read(handle, :chunk_size => 4096,
        :progress_callback => lambda { |data| print "." })
      puts
    ensure
      STDOUT.sync = false
    end
  end
How do I… ...manage file permissions? I want to query a file’s permissions…

File permissions are one of the stat attributes of files and directories:

  p sftp.stat("/path/to/remote.file").permissions
How do I… ...manage file permissions? I want to change a file’s permissions…

Just use setstat to change the permissions of an existing file:

  sftp.setstat("/path/to/remote.file", :permissions => 0644)
How do I… ...manage file permissions? I already have an open handle for the remote file…

If you have a handle for the remote file, you can use fstat and fsetstat to query and set the permissions:

  sftp.open_handle("/path/to/remote.file") do |handle|
    permissions = sftp.fstat(handle)
    sftp.fsetstat(handle, :permissions => permissions | 0444)
  end
How do I… ...manage directories? I want to query the contents of a directory…

You query the contents of a directory by calling opendir to obtain a handle to the directory, and then using readdir on the handle to obtain a list of directory entries. Be sure to close the handle when you’re done:

  handle = sftp.opendir("/usr/lib")
  items = sftp.readdir(handle)
  items.each do |item|
    puts item.filename
    puts item.longname
    p item.attributes # permissions, atime, etc.
  end
  sftp.close_handle(handle)
How do I… ...manage directories? I want to create a directory…

Use mkdir:

  sftp.mkdir("/path/to/remote/dir", :permissions => 0500)
How do I… ...manage directories? I want to remove a directory…

Use rmdir:

  sftp.rmdir("/path/to/remote/dir")
How do I… ...delete a file?

Use remove:

  sftp.remove("/path/to/remote.file")
How do I… ...rename a file?

Use rename:

  sftp.rename("/path/to/remote.file", "/path/to/new.file")

It should be noted that rename is only supported by version 2 or later of the SFTP protocol, so if you’re using an older SFTP server you might not be able to use this operation.