Checking to See If a File Exists
Problem
Given a filename, you want to see whether the corresponding file exists and is the right kind for your purposes.
Solution
Most of the time you'll use the File.file? predicate, which returns true only if the file is an existing regular file (that is, not a directory, a socket, or some other special file).
filename = 'a_file.txt' File.file? filename # => false require 'fileutils' FileUtils.touch(filename) File.file? filename # => true
Use the File.exists? predicate instead if the file might legitimately be a directory or other special file, or if you plan to create a file by that name if it doesn't exist. File.exists? will return true if a file of the given name exists, no matter what kind of file it is.
directory_name = 'a_directory' FileUtils.mkdir(directory_name) File.file? directory_name # => false File.exists? directory_name # => true
Discussion
A true response from File.exists? means that the file is present on the filesystem, but says nothing about what type of file it is. If you open up a directory thinking it's a regular file, you're in for an unpleasant surprise. This is why File.file? is usually more useful than File.exists?.
Ruby provides several other predicates for checking the type of a file: the other commonly useful one is File.directory?:
File.directory? directory_name # => true File.directory? filename # => false
The rest of the predicates are designed to work on Unix systems. File.blockdev? tests or block-device files (such as hard-drive partitions), File.chardev? tests for character-device files (such as TTYs), File.socket? tests for socket files, and File.pipe? tests for named pipes,
File.blockdev? '/dev/hda1' # => true File.chardev? '/dev/tty1' # => true File.socket? '/var/run/mysqld/mysqld.sock' # => true system('mkfifo named_pipe') File.pipe? 'named_pipe' # => true
File.symlink? tests whether a file is a symbolic link to another file, but you only need to use it when you want to treat symlinks differently from other files. A symlink to a regular file will satisfy File.file?, and can be opened and used just like a regular file. In most cases, you don't even have to know it's a symlink. The same goes for symlinks to directories and to other types of files.
new_filename = "#{filename}2" File.symlink(filename, new_filename) File.symlink? new_filename # => true File.file? new_filename # => true
All of Ruby's file predicates return false if the file doesn't exist at all. This means you can test "exists and is a directory" by just testing directory?; it's the same for the other predicates.
See Also
- Recipe 6.8, "Writing to a Temporary File," and Recipe 6.14, "Backing Up to Versioned Filenames," deal with writing to files that don't currently exist