Virtual File System - simple and unified API over different storages (Local, S3, SFTP, ...)
Ruby CSS
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Virtual File System provides clean, simple and unified API over different storages (Local File System, AWS S3, SFTP, ...).

  • very simple and intuitive API.
  • same API for different storages.
  • work simultaneously with multiple storages.
  • small codebase, easy to learn and extend.
  • driver implementation is very simple, it is easy to create new drivers.

Such unified API is possible because although the API of storages are different the core concept are almost the same.

Install Vfs with Rubygems:

gem install vfs

Once installed, You can proceed with the basic example, there's also S3 version and SFTP version (also S3 backup and SSH/SFTP deployment examples availiable).

You can report bugs and discuss features on the issues page.


# Preparing sandbox for our sample and cleaning it before starting
# (ignore the `$sandbox` variable, it's needed to reuse this code in S3 and SSH samples).
require 'vfs'
sandbox = $sandbox || '/tmp/vfs_sandbox'.to_dir.delete

# Creating simple Hello World project.
project = sandbox['hello_world']

# Writing readme file (note that parent dirs where created automatically).
project['readme.txt'].write 'My App'

# We can assign files and dirs to variables, now the `readme` variable refers to our
# readme.txt file.
readme = project['readme.txt']

# Let's ensure that it's all ok with our readme file and check its attributes.
p                               # => readme.txt
p [readme.basename, readme.extension]       # => ['readme', 'txt']
p readme.path                               # => /.../readme.txt
p readme.exist?                             # => true
p readme.file?                              # => true
p readme.dir?                               # => false
p readme.size                               # => 6
p readme.created_at                         # => 2011-09-09 13:20:43 +0400
p readme.updated_at                         # => 2011-09-09 13:20:43 +0400

# Reading - You can read all at once or do it sequentially (input stream
# will be automatically splitted into chunks of reasonable size).
p                               # => "My shiny App"{|chunk| p chunk}                # => "My shiny App"

# The same for writing - write all at once or do it sequentially
# (if there's no file it will be created, if it exists it will be rewriten).
readme.write "My App v2"
readme.write{|stream| stream.write "My App v3"}
p                               # => "My shiny App v3"

# Appending content to existing file.
readme.append "How to install ..."
p readme.size                               # => 27

# Copying and Moving. It also works exactly the same
# way if You copy or move files and dirs to other storages.
readme.copy_to project['docs/readme.txt']
p project['docs/readme.txt'].exist?         # => true
p readme.exist?                             # => true

readme.move_to project['docs/readme.txt']
p project['docs/readme.txt'].exist?         # => true
p readme.exist?                             # => false

# Let's add empty Rakefile to our project.

# Operations with directories - checking our project exists and not empty.
p project.exist?                            # => true
p project.empty?                            # => false

# Listing dir content. There are two versions of methods -
# without block the result will be Array of Entries, with block
# it will iterate over directory sequentially.
p project.entries                           # => [/.../docs, /.../Rakefile]
p project.files                             # => [/.../Rakefile]
p project.dirs                              # => [/.../docs]
project.entries do |entry|                  # => ["docs", false]
  p [, entry.file?]               # => ["Rakefile", true]
p project.include?('Rakefile')              # => true

# You can also use glob (if storage support it).
if project.driver.local?
  p project.entries('**/Rake*')             # => [/.../Rakefile]
  p project['**/Rake*']                     # => [/.../Rakefile]

# The result of dir listing is just an array of Entries, so
# You can use it to do interesting things. For example this code will
# calculates the size of sources in our project.
if project.driver.local?
  project['**/*.rb'].collect(&:size).reduce(0, :+)

# Copying and moving - let's create another project by cloning our hello_world.
project.copy_to sandbox['another_project']
p sandbox['another_project'].entries        # => [/.../docs, .../Rakefile]

# Cleaning sandbox.

Integration with Vos (Virtual Operating System)

Vfs can be used toghether with the Virtual Operating System Tool, and while the Vfs covers all the I/O operations the Vos provides support for remote command execution. You can use this combination to fully control remote machines, for example - I'm using it to manage my production servers (setup, administration, deployment, migration, ...).

For more details please go to Vos project page. You can also take look at the actual configuration I'm using to control my servers My Cluster (in conjunction with small configuration tool Cluster Management).


To easy my work: with local FS, remote FS, and some specific systems like Hadoop DFS.

Because the API of standard File/Dir/FileUtils classes are just terrible. And there's the reason for it - the goal of thouse tools is to provide 1-to-1 clone of underlying OS API, instead of provididing handy tool.

And if you want to use remote FS - things are getting even worse and more complicated (Net::SSH & Net::SFTP use a little different API than local FS, and you has to remember all thouse little quirks).

Generate documentation

cd docs && docco -o site *.rb



Copyright (c) Alexey Petrushin, released under the MIT license.