# Net::SFTP FAQ

- What is Net::SFTP?
- How do I…
  - ...connect to an SFTP server?
    - I’d like to connect without first getting a Net::SSH connection…
    - I already have an open Net::SSH connection…
  - ...upload data?
    - I want to upload an entire file on disk…
    - I want to upload bytes from a string or other object…
  - ...download data?
    - I want to download directly to a local file…
    - I want to download to a string in memory…
    - I want to be notified of the progress of the download…
  - ...manage file permissions?
    - I want to query a file’s permissions…
    - I want to change a file’s permissions…
    - I already have an open handle for the remote file…
  - ...manage directories?
    - I want to query the contents of a directory…
    - I want to create a directory…
    - I want to remove a directory…
  - ...delete a file?
  - ...rename a file?

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.