The File
class defines quite a few class methods for working with files as
entries in a filesystem: methods for testing the size or existence of a
named file, for example, and methods for separating a filename from the
directory name that precedes it. These are class methods and they do not
operate on File
objects; instead,
filenames are specified as strings. Similarly, the Dir
class defines
class methods for working with and reading filenames from filesystem
directories. The subsections that follow demonstrate how to:
Work with and manipulate filenames and directory names
List directories
Test files to determine their type, size, modification time, and other attributes
Delete, rename, and perform similar operations on files and directories
Note that the methods described here query and manipulate files, but do not read or write file content. Reading and writing files is covered in Input/Output.
The class methods of the File
and Dir
classes operate on files
and directories specified by name. Ruby uses Unix-style filenames with
/
as the directory separator character. You can use the
forward slash character in your filenames, even when using Ruby on a
Windows platform. On Windows, Ruby can also handle filenames that use the
backslash character and that include drive letter prefixes. The
constant File::SEPARATOR
should
be '/'
in all
implementations. File::ALT_SEPARATOR
is ''
on Windows, and is nil
on other
platforms.
The File
class defines some
methods for manipulating filenames:
full = '/home/matz/bin/ruby.exe' file=File.basename(full) # => 'ruby.exe': just the local filename File.basename(full, '.exe') # => 'ruby': with extension stripped dir=File.dirname(full) # => '/home/matz/bin': no / at end File.dirname(file) # => '.': current directory File.split(full) # => ['/home/matz/bin', 'ruby.exe'] File.extname(full) # => '.exe' File.extname(file) # => '.exe' File.extname(dir) # => '' File.join('home','matz') # => 'home/matz': relative File.join('','home','matz') # => '/home/matz': absolute
The File.expand_path
method converts a relative path to a fully qualified path. If
the optional second argument is supplied, it is first prepended as a
directory to the first argument. The result is then converted to an
absolute path. If it begins with a Unix-style ~
, the directory is relative to the current
user or specified user’s home directory. Otherwise, the directory is
resolved relative to the current working directory (see Dir.chdir
below to change the working
directory):
Dir.chdir("/usr/bin") # Current working directory is "/usr/bin" File.expand_path("ruby") # => "/usr/bin/ruby" File.expand_path("~/ruby") # => "/home/david/ruby" File.expand_path("~matz/ruby") # => "/home/matz/ruby" File.expand_path("ruby", "/usr/local/bin") # => "/usr/local/bin/ruby" File.expand_path("ruby", "../local/bin") # => "/usr/local/bin/ruby" File.expand_path("ruby", "~/bin") # => "/home/david/bin/ruby"
The File.identical?
method tests whether two filenames refer to the same file.
This might be because the names are the same, but it is a more useful
method when the names differ. Two different names might refer to the
same file if one is a relative filename and the other is absolute, for
example. One might include “..
” to
go up a level and then down again. Or, two different names might refer
to the same file if one name is a symbolic link or shortcut (or hard
link on platforms that support it) to the other. Note, however, that
File.identical?
only returns
true
if the two names refer to the
same file and that file actually exists. Also note that File.identical?
does not expand the ~
character for home directories the way
that File.expand_path
does:
File.identical?("ruby", "ruby") # => true if the file exists File.identical?("ruby", "/usr/bin/ruby") # => true if CWD is /usr/bin File.identical?("ruby", "../bin/ruby") # => true if CWD is /usr/bin File.identical?("ruby", "ruby1.9") # => true if there is a link
Finally, File.fnmatch
tests
whether a filename matches a specified pattern. The pattern is
not a regular expression, but is like the file-matching patterns used
in shells. “?
” matches a single
character. “*
” matches any
number of characters. And “**
”
matches any number of directory levels. Characters in square brackets
are alternatives, as in regular expressions. fnmatch
does not allow alternatives in curly
braces (as the Dir.glob
method
described below does). fnmatch
should usually be invoked with a third argument of File::FNM_PATHNAME
, which prevents “*
”
from matching “/
”. Add File::FNM_DOTMATCH
if you want “hidden”
files and directories whose names begin with “.
” to match. Only a few examples of fnmatch
are given here. Use ri File.fnmatch
for complete details. Note
that File.fnmatch?
is a
synonym:
File.fnmatch("*.rb", "hello.rb") # => true File.fnmatch("*.[ch]", "ruby.c") # => true File.fnmatch("*.[ch]", "ruby.h") # => true File.fnmatch("?.txt", "ab.txt") # => false flags = File::FNM_PATHNAME | File::FNM_DOTMATCH File.fnmatch("lib/*.rb", "lib/a.rb", flags) # => true File.fnmatch("lib/*.rb", "lib/a/b.rb", flags) # => false File.fnmatch("lib/**/*.rb", "lib/a.rb", flags) # => true File.fnmatch("lib/**/*.rb", "lib/a/b.rb", flags) # => true
The easiest way to list the contents of a directory is with
the Dir.entries
method
or the Dir.foreach
iterator:
# Get the names of all files in the config/ directory filenames = Dir.entries("config") # Get names as an array Dir.foreach("config") {|filename| ... } # Iterate names
The names returned by these methods are not guaranteed to be in
any particular order, and (on Unix-like platforms) include “.
” (the
current directory) and “..
” (the
parent directory). To obtain a list of files that match a given
pattern, use the Dir.[]
operator:
Dir['*.data'] # Files with the "data" extension Dir['ruby.*'] # Any filename beginning with "ruby." Dir['?'] # Any single-character filename Dir['*.[ch]'] # Any file that ends with .c or .h Dir['*.{java,rb}'] # Any file that ends with .java or .rb Dir['*/*.rb'] # Any Ruby program in any direct sub-directory Dir['**/*.rb'] # Any Ruby program in any descendant directory
A more powerful alternative to Dir[]
is Dir.glob
. (The verb “glob” is an old Unix term for filename
matching in a shell.) By default, this method works like Dir[]
, but if passed a block, it yields the
matching filenames one at a time rather than returning an array. Also,
the glob
method accepts an optional
second argument. If you pass the constant File::FNM_DOTMATCH
(see File.fnmatch
previously) as this second
argument, then the result will include files whose names begin with
“.
” (on Unix systems, these files
are hidden and are not returned
by default):
Dir.glob('*.rb') {|f| ... } # Iterate all Ruby files Dir.glob('*') # Does not include names beginning with '.' Dir.glob('*',File::FNM_DOTMATCH) # Include . files, just like Dir.entries
The directory listing methods shown here, and all File
and Dir
methods that resolve relative pathnames,
do so relative to the “current working directory,” which is a value
global to the Ruby interpreter process. Query and set the CWD with the
getwd
and chdir
methods:
puts Dir.getwd # Print current working directory Dir.chdir("..") # Change CWD to the parent directory Dir.chdir("../sibling") # Change again to a sibling directory Dir.chdir("/home") # Change to an absolute directory Dir.chdir # Change to user's home directory home = Dir.pwd # pwd is an alias for getwd
If you pass a block to the chdir
method, the directory will be restored
to its original value when the block exits. Note, however, that while
the directory change is limited in duration, it is still global in
scope and affects other threads. Two threads may not call Dir.chdir
with a block at the same time.
File
defines a slew of methods to obtain metadata about a named file
or directory. Many of the methods return low-level information that is
OS-dependent. Only the most portable and broadly useful are
demonstrated here. Use ri on the File
and File::Stat
classes for a complete list of methods.
The following simple methods return basic information about a
file. Most are predicates that return true
or false
:
f = "/usr/bin/ruby" # A filename for the examples below # File existence and types. File.exist?(f) # Does the named file exist? Also: File.exists? File.file?(f) # Is it an existing file? File.directory?(f) # Or is it an existing directory? File.symlink?(f) # Either way, is it a symbolic link? # File size methods. Use File.truncate to set file size. File.size(f) # File size in bytes. File.size?(f) # Size in bytes or nil if empty file. File.zero?(f) # True if file is empty. # File permissions. Use File.chmod to set permissions (system dependent). File.readable?(f) # Can we read the file? File.writable?(f) # Can we write the file? No "e" in "writable" File.executable?(f) # Can we execute the file? File.world_readable?(f) # Can everybody read it? Ruby 1.9. File.world_writable?(f) # Can everybody write it? Ruby 1.9. # File times/dates. Use File.utime to set the times. File.mtime(f) # => Last modification time as a Time object File.atime(f) # => Last access time as a Time object
Another way to determine the type (file, directory, symbolic
link, etc.) of a filename is with ftype
, which returns a string that names the
type. Assume that /usr/bin/ruby
is a symbolic link (or shortcut) to /usr/bin/ruby1.9
:
File.ftype("/usr/bin/ruby") # => "link" File.ftype("/usr/bin/ruby1.9") # => "file" File.ftype("/usr/lib/ruby") # => "directory" File.ftype("/usr/bin/ruby3.0") # SystemCallError: No such file or directory
If you are interested in multiple pieces of information about a
file, it may be more efficient to call stat
or lstat
. (stat
follows symbolic links; lstat
returns information about the link
itself.) These methods return a File::Stat
object, which has instance
methods with the same names (but without arguments) as the class
methods of File
. The efficiency of
using stat
is that Ruby only has to
make one call to the OS to obtain all file metadata. Your Ruby program
can then obtain that information from the File::Stat
object as it needs it:
s = File.stat("/usr/bin/ruby") s.file? # => true s.directory? # => false s.ftype # => "file" s.readable? # => true s.writable? # => false s.executable? # => true s.size # => 5492 s.atime # => Mon Jul 23 13:20:37 -0700 2007
Use ri on File::Stat
for a full list of its methods.
One final general-purpose file testing method is Kernel.test
. It exists for historical
compatibility with the Unix shell command test. The
test
method is largely obviated by the class methods of the
File
class, but you may see it used
in existing Ruby scripts. Use ri for complete
details:
# Testing single files test ?e, "/usr/bin/ruby" # File.exist?("/usr/bin/ruby") test ?f, "/usr/bin/ruby" # File.file?("/usr/bin/ruby") test ?d, "/usr/bin/ruby" # File.directory?("/usr/bin/ruby") test ?r, "/usr/bin/ruby" # File.readable?("/usr/bin/ruby") test ?w, "/usr/bin/ruby" # File.writeable?("/usr/bin/ruby") test ?M, "/usr/bin/ruby" # File.mtime("/usr/bin/ruby") test ?s, "/usr/bin/ruby" # File.size?("/usr/bin/ruby") # Comparing two files f and g test ?-, f, g # File.identical(f,g) test ?<, f, g # File(f).mtime < File(g).mtime test ?>, f, g # File(f).mtime > File(g).mtime test ?=, f, g # File(f).mtime == File(g).mtime
The File
class does not define any special methods for creating a file.
To create one, simply open it for writing, write zero or more bytes,
and close it again. If you don’t want to clobber an existing file,
open it in append mode:
# Create (or overwrite) a file named "test" File.open("test", "w") {} # Create (but do not clobber) a file named "test" File.open("test", "a") {}
To copy a file, use File.copy_stream
, specifying filenames as the source and
destination:
File.copy_stream("test", "test.backup")
To change the name of a file, use File.rename
:
File.rename("test", "test.old") # Current name, then new name
To create a symbolic link to a file, use File.symlink
:
File.symlink("test.old", "oldtest") # Link target, link name
On systems that support it, you can create a “hard
link” with File.link
:
File.link("test.old", "test2") # Link target, link name
Finally, to delete a file or link, use File.delete
, or its synonym File.unlink
:
File.delete("test2") # May also be called with multiple args File.unlink("oldtest") # to delete multiple named files
On systems that support it, use File.truncate
to truncate a file to a
specified number (possibly zero) of bytes. Use File.utime
to set the access and modification times of a file. And
use the platform-dependent method File.chmod
to change the permissions of a
file:
f = "log.messages" # Filename atime = mtime = Time.now # New access and modify times File.truncate(f, 0) # Erase all existing content File.utime(atime, mtime, f) # Change times File.chmod(0600, f) # Unix permissions -rw-------; note octal arg
To create a new directory, use Dir.mkdir
. To delete a directory, use Dir.rmdir
or one of its synonyms, Dir.delete
or Dir.unlink
. The directory must be empty
before it can be deleted:
Dir.mkdir("temp") # Create a directory File.open("temp/f", "w") {} # Create a file in it File.open("temp/g", "w") {} # Create another one File.delete(*Dir["temp/*"]) # Delete all files in the directory Dir.rmdir("temp") # Delete the directory
3.139.83.199