NAME
Sidef::Types::Glob::File - File manipulation and information retrieval
DESCRIPTION
This class provides an interface for file operations in Sidef: reading, writing, metadata retrieval, and filesystem manipulation. It's a subclass of Sidef::Types::String::String -- a File object is really just a path string with file-specific methods layered on top, so ordinary string methods work on it too.
Nearly every method here also works when called directly on the File class itself (e.g. File.exists("/tmp/x")), not just on an instance -- the implementation shifts the class off the argument list and treats the next argument as the path.
SYNOPSIS
var file = File("example.txt")
# Create and write to a file
file.write("Hello, World!")
# Read file contents
say(file.read)
# Check file properties
if (file.exists && file.is_readable) {
say("File exists and is readable")
}
# Get file information
say("Size: #{file.size} bytes")
say("Directory: #{file.dirname}")
say("Basename: #{file.basename}")
# Copy and move files
file.copy("backup.txt")
file.move("new_location.txt")
# Work with paths
var abs_path = file.abs_path
say("Absolute path: #{abs_path}")
INHERITS
Inherits methods from Sidef::Types::String::String.
CONSTRUCTION
new
File(path)
File(*path_components)
File.new(path)
Creates a new File object. With a single argument, path is used as-is (stringified first, if it isn't already a plain string). With more than one argument, the arguments are joined as path components (via File::Spec::catfile, so the platform's own directory separator is used) into a single path.
var file = File.new("/path/to/file.txt")
var file2 = File("/path/to/file.txt") # same as above
var file3 = File("path", "to", "file.txt") # joined: "path/to/file.txt"
Aliases: call
PATH COMPONENTS
name
file.name
Returns the file's path exactly as given (or as joined, if constructed from multiple components), as a String -- this does not make it absolute or otherwise normalize it.
var file = File("/home/user/file.txt")
say(file.name) #=> "/home/user/file.txt"
basename
file.basename
Returns just the filename portion of the path (without any directory component), like the Unix basename command.
var file = File("/home/user/document.txt")
say(file.basename) #=> "document.txt"
Aliases: base, base_name
dirname
file.dirname
Returns the directory portion of the path, as a Dir object (not a plain String), like the Unix dirname command.
var file = File("/home/user/documents/file.txt")
say(file.dirname) #=> Dir("/home/user/documents")
Aliases: dir, dir_name
split
file.split
Splits the path into its directory components (and filename), via File::Spec::splitdir, and returns them as an Array of Strings.
var file = File("/home/user/docs/file.txt")
say(file.split) #=> ["", "home", "user", "docs", "file.txt"]
splitpath
file.splitpath
Splits the path into volume, directory, and filename components, via File::Spec::splitpath, and returns them as a 3-element Array.
var file = File("/home/user/file.txt")
var (vol, dir, name) = file.splitpath...
# vol: "", dir: "/home/user/", name: "file.txt"
is_absolute
file.is_absolute
Returns true if the path is absolute, false if it's relative.
say(File("/home/user/file.txt").is_absolute) #=> true
say(File("relative/path.txt").is_absolute) #=> false
Aliases: is_abs
abs_name
file.abs_name(base=Dir.cwd)
Returns a new File with the path resolved to an absolute one, using base (or the current working directory, if omitted) for any relative component. This does not resolve symlinks or ./.. segments -- see "abs_path" for that.
var file = File("docs/readme.txt")
say(file.abs_name) # e.g. "/home/user/docs/readme.txt"
say(file.abs_name("/var/www")) #=> "/var/www/docs/readme.txt"
Aliases: abs, absname, rel2abs
rel_name
file.rel_name(base=Dir.cwd)
Computes a path relative to base.
var file = File("/home/user/docs/file.txt")
say(file.rel_name("/home/user")) # returns "docs/file.txt"
Aliases: rel, relname, abs2rel
abs_path
file.abs_path
Returns a new File with the canonical absolute path: symlinks, ., and .. are all resolved, giving the real physical path on the filesystem.
var file = File("../project/link_to_file")
say(file.abs_path) # e.g. "/home/user/project/actual_file"
Aliases: realpath
FILE TYPE TESTS
exists
file.exists
Returns true if something exists at the path (of any type -- regular file, directory, symlink, etc.), otherwise false.
File("data.txt").exists || die("File not found")
is_file
file.is_file
Returns true if the path is a plain (regular) file, otherwise false.
File("document.txt").is_file && say("Regular file")
is_directory
file.is_directory
Returns true if the path is a directory, otherwise false.
File("/home/user").is_directory && say("This is a directory")
Aliases: is_dir
is_link
file.is_link
Returns true if the path is a symbolic link, false otherwise (including if the filesystem doesn't support symlinks at all).
File("shortcut").is_link && say("This is a symlink")
is_socket
file.is_socket
Returns true if the path is a Unix domain socket.
File("/var/run/socket").is_socket && say("This is a socket")
is_block
file.is_block
Returns true if the path is a block special file (block device).
File("/dev/sda1").is_block && say("Block device")
is_char_device
file.is_char_device
Returns true if the path is a character special file (character device).
File("/dev/tty").is_char_device && say("Character device")
is_empty
file.is_empty
Returns true if the file has zero size.
File("empty.txt").is_empty && say("File is empty")
is_binary
file.is_binary
Returns true if the file's contents heuristically look binary (Perl's own -B test: a probe of the file's opening bytes).
File("image.png").is_binary && say("Binary file detected")
is_text
file.is_text
Returns true if the file's contents heuristically look like ASCII/UTF-8 text (Perl's own -T test; the logical opposite of "is_binary" for most files).
File("readme.txt").is_text && say("Text file detected")
PERMISSIONS AND OWNERSHIP
Each pair below (is_X / is_real_X) checks the same permission bit, but against different user/group IDs: the plain form uses the process's effective UID/GID (what actually governs access, and can differ under setuid/setgid programs), while the real_ form uses the process's real UID/GID (who actually invoked it).
is_readable
file.is_readable
Returns true if the file is readable, checked against the effective UID/GID.
File("data.txt").is_readable || die("Cannot read file")
is_writeable
file.is_writeable
Returns true if the file is writable, checked against the effective UID/GID.
File("output.log").is_writeable || die("Cannot write to file")
is_executable
file.is_executable
Returns true if the file is executable, checked against the effective UID/GID.
File("run.sh").is_executable || die("Script is not executable")
is_owned
file.is_owned
Returns true if the file is owned by the effective UID of the current process.
File("myfile.txt").is_owned && say("You own this file")
is_real_readable
file.is_real_readable
Like "is_readable", but checked against the real (not effective) UID/GID.
is_real_writeable
file.is_real_writeable
Like "is_writeable", but checked against the real (not effective) UID/GID.
is_real_executable
file.is_real_executable
Like "is_executable", but checked against the real (not effective) UID/GID.
is_real_owned
file.is_real_owned
Returns true if the file is owned by the real (not effective) UID of the current process.
has_setuid_bit
file.has_setuid_bit
Returns true if the file's setuid bit is set (an executable with this bit runs with its owner's privileges).
File("/usr/bin/sudo").has_setuid_bit && say("Has setuid bit")
has_setgid_bit
file.has_setgid_bit
Returns true if the file's setgid bit is set (an executable with this bit runs with its group's privileges).
File("/usr/bin/wall").has_setgid_bit && say("Has setgid bit")
has_sticky_bit
file.has_sticky_bit
Returns true if the file's sticky bit is set.
File("/tmp").has_sticky_bit && say("Has sticky bit")
TIMESTAMPS
modification_time_days_diff
var days = File("foo.txt").modification_time_days_diff
Returns the number of days since the file was last modified.
The returned value is a fractional number, where the integer part represents whole days and the fractional part represents the elapsed portion of the current day.
This method is equivalent to Perl's -M file test operator.
Example:
say File("log.txt").modification_time_days_diff #=> 2.34
access_time_days_diff
var days = File("foo.txt").access_time_days_diff
Returns the number of days since the file was last accessed.
The returned value is a fractional number, where the integer part represents whole days and the fractional part represents the elapsed portion of the current day.
This method is equivalent to Perl's -A file test operator.
Example:
say File("notes.txt").access_time_days_diff #=> 0.08
change_time_days_diff
var days = File("foo.txt").change_time_days_diff
Returns the number of days since the file's inode status was last changed.
On Unix-like systems, this corresponds to the last metadata change (such as permissions, ownership, or renaming), and is not necessarily the same as the last modification of the file contents.
The returned value is a fractional number, where the integer part represents whole days and the fractional part represents the elapsed portion of the current day.
This method is equivalent to Perl's -C file test operator.
Example:
say File("script.pl").change_time_days_diff #=> 1.75
utime
file.utime(atime, mtime)
Sets the file's access and modification times (as Unix timestamps). Returns true on success, false otherwise.
var now = Time.now.to_i
File("data.txt").utime(now, now)
stat
file.stat
Returns a Stat object with the file's metadata (size, permissions, timestamps, inode number, etc.). If the path is a symbolic link, this reports on the target, not the link -- see "lstat" for the link itself.
var info = File("data.txt").stat
say("Size: #{info.size}")
lstat
file.lstat
Like "stat", but if the path is a symbolic link, reports on the link itself rather than following it to its target.
READING AND WRITING CONTENT
size
file.size
Returns the size of the file in bytes.
say("File size: #{File("document.txt").size} bytes")
read
file.read(layer="utf8")
Reads and returns the entire contents of the file as a String, decoded through the given PerlIO layer (without a leading colon -- just the layer name itself, e.g. "utf8" or "raw"). Defaults to UTF-8. Returns nil if the file can't be opened.
var content = File("data.txt").read # read as UTF-8 text
var binary = File("data.bin").read("raw") # read as raw bytes
write
file.write(string, layer="utf8")
Writes string to the file, replacing any existing content (creating the file if it doesn't exist), through the given PerlIO layer (again, no leading colon). Returns true on success, or nil/false otherwise -- not the File object itself, so this can't be chained.
File("output.txt").write("Hello, World!")
File("output.bin").write(binary_data, "raw")
append
file.append(string, layer="utf8")
Appends string to the end of the file (creating it if it doesn't exist), through the given PerlIO layer (no leading colon). Returns true on success, or nil/false otherwise -- not the File object itself.
File("log.txt").append("New log entry\n")
edit
file.edit(block)
Rewrites the file in place, one line at a time: block is called once per line (each as a String, including its line terminator), and the collected return values of every call replace the file's entire content. block does not receive the whole file at once.
File("text.txt").edit {|line| line.uc }
File("config.ini").edit {|line| line.gsub(/old_value/, "new_value") }
md5
file.md5
Returns the MD5 hash of the file's contents, as a hex string.
say("MD5: #{File("data.bin").md5}")
sha1
file.sha1
Returns the SHA-1 hash of the file's contents, as a hex string.
sha256
file.sha256
Returns the SHA-256 hash of the file's contents, as a hex string.
sha512
file.sha512
Returns the SHA-512 hash of the file's contents, as a hex string.
compare
file.compare(other)
Compares the byte contents of self and other. Returns 0 if identical, -1 if self sorts before other, 1 if after, or nil on error.
given (File("a.txt").compare(File("b.txt"))) {
when (0) { say("Files are identical") }
default { say("Files differ") }
}
OPENING FILES
open
file.open(mode="<:utf8", fh_ref=nil, err_ref=nil)
Opens the file with a raw Perl-style mode string (e.g. '<', ''>, '>'>, '+<', each optionally suffixed with an encoding layer like ':utf8'). If fh_ref is given, the resulting FileHandle is stored through that reference and this returns true/false for success (storing any error message through err_ref, if given); otherwise, it returns the FileHandle directly (or nil on failure).
var fh = nil
var err = nil
if (File("data.txt").open('<', \fh, \err)) {
fh.close
} else {
die(err)
}
open_r
file.open_r(*args)
Opens the file for reading (UTF-8). Equivalent to self.open('<:utf8', *args) -- see "open" for what args can do.
var fh = File("input.txt").open_r
Aliases: open_read
open_w
file.open_w(*args)
Opens the file for writing (UTF-8), truncating any existing content. Equivalent to self.open(':utf8', *args)>.
var fh = File("output.txt").open_w
Aliases: open_write
open_a
file.open_a(*args)
Opens the file for appending (UTF-8), creating it if needed. Equivalent to self.open('>:utf8', *args)>.
var fh = File("log.txt").open_a
Aliases: open_append
open_rw
file.open_rw(*args)
Opens the file for both reading and writing (UTF-8), without truncating. Equivalent to self.open('+<:utf8', *args).
Aliases: open_read_write
open_arw
file.open_arw(*args)
Opens the file for appending, reading, and writing (UTF-8). Equivalent to self.open('+>:utf8', *args)>.
Aliases: open_append_read_write
opendir
file.opendir(*args)
Treats the path as a directory and opens it (equivalent to Dir(self).open(*args)), returning a directory handle for reading entries.
var dh = File("/home/user").opendir
dh.each {|entry| say(entry) }
sysopen
file.sysopen(var_ref, mode, perm=0666)
Opens the file using Perl's low-level sysopen, with numeric mode flags (see "FCNTL CONSTANTS" below) and perm permission bits. Stores the resulting FileHandle through var_ref. Returns true on success, false otherwise.
var fh = nil
File("data.bin").sysopen(\fh, O_RDWR | O_CREAT, 0644)
touch
file.touch(*args)
Creates the file if it doesn't already exist (by opening it in append mode, via "open_a", and forwarding args the same way "open" does). For a file that already exists, this mostly leaves it untouched -- it does not reliably update the modification/access times the way the Unix touch command does.
File("newfile.txt").touch
Aliases: make, mkfile, create
mktemp
File.mktemp(%options)
Creates a new temporary file (via File::Temp) and returns an already-open FileHandle for it -- not a plain File object. %options are forwarded to File::Temp::tempfile (e.g. template and dir).
var tmp = File.mktemp
tmp.say("temporary data")
var tmp2 = File.mktemp(template => "myapp_XXXXXX", dir => "/var/tmp")
Aliases: make_tmp, make_temp
FCNTL CONSTANTS
Every constant exported by Perl's core Fcntl module (O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_APPEND, O_TRUNC, SEEK_SET, SEEK_CUR, SEEK_END, LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB, and so on) is exposed as a method on File that returns its value as a Number, computed and cached on first use. These are mainly useful as flags for "sysopen".
say(File.O_RDWR | File.O_CREAT)
FILESYSTEM OPERATIONS
rename
file.rename(new_name)
Renames the file on disk to new_name. Returns true on success, false otherwise. Note that self's own stored path is not updated to the new name -- construct a new File if you need to keep using it under the new name.
File("old.txt").rename("new.txt")
move
file.move(destination)
Moves the file to destination (a filename, or a File/Dir object). Returns true on success, false otherwise. As with "rename", self's own stored path is not updated.
File("old_name.txt").move("new_name.txt")
File("old_name.txt").move(Dir("archive"))
Aliases: mv
copy
file.copy(destination)
Copies the file to destination (a filename, or a File/Dir object). Returns true on success, false otherwise.
File("source.txt").copy("backup.txt")
Aliases: cp
link
file.link(new_name)
Creates a hard link named new_name pointing to the same inode as file. Returns true on success, false otherwise.
File("source.txt").link("hardlink.txt")
symlink
file.symlink(link_name)
Creates a symbolic link named link_name pointing to file (which doesn't need to exist yet). Returns true on success, false otherwise.
File("original.txt").symlink("link_to_original")
readlink
file.readlink
Reads the target of a symbolic link, returning it as a Dir object if the target is itself a directory, or as a File object otherwise. If the path isn't actually a symbolic link, the returned object wraps an undefined path rather than being nil outright.
var target = File("shortcut").readlink
Aliases: read_link
chown
file.chown(uid, gid)
Changes the file's owner and group (as numeric IDs). Returns true on success, false otherwise. May require elevated privileges.
File("data.txt").chown(1000, 1000)
chmod
file.chmod(permission)
Changes the file's permission bits. Returns true on success, false otherwise.
File("script.sh").chmod(0755)
truncate
file.truncate(length=0)
Truncates the file to length bytes (extending with null bytes if the file was shorter). Returns true on success, false otherwise.
File("data.txt").truncate(100)
unlink
file.unlink
File.unlink(*paths)
Called on an instance, deletes just that file and returns true/false. Called on the File class itself with a list of paths, deletes each one and returns the Number of files successfully deleted (not a boolean).
File("temp.txt").unlink #=> true or false
File.unlink("file1.txt", "file2.txt") #=> a count, e.g. 2
delete
file.delete
File.delete(*paths)
Like "unlink", but called on an instance, returns true/false; called on the class with a list of paths, returns the count of files successfully deleted.
File("temporary.txt").delete && say("File deleted successfully")
Aliases: remove
CONVERSION
to_str
file.to_str
Returns the file's path as a plain String.
say(File("/home/user/file.txt").to_str) #=> "/home/user/file.txt"
Aliases: to_s
dump
file.dump
Returns a String representation of the File object for debugging, in the format File("path").
say(File("example.txt").dump) #=> File("example.txt")
to_file
file.to_file
Returns self unchanged. Useful in polymorphic code that might receive either a plain String or an already-constructed File object and wants to normalize to the latter.
get_value
file.get_value
Returns the raw underlying path string (unwrapped from the File object). A low-level method, mainly useful for interop rather than everyday Sidef code.
EXAMPLES
Basic file operations
var file = File("example.txt")
file.write("Line 1\nLine 2\nLine 3\n")
say(file.read)
file.append("Line 4\n")
say("Size: #{file.size} bytes")
say("Readable: #{file.is_readable}")
say("Writable: #{file.is_writeable}")
File information and metadata
var file = File("/etc/passwd")
say("Directory: #{file.dirname}")
say("Basename: #{file.basename}")
say("Absolute path: #{file.abs_path}")
var info = file.stat
say("Inode: #{info.ino}")
say("Owner UID: #{info.uid}")
Checksums
var file = File("download.iso")
say("MD5: #{file.md5}")
say("SHA256: #{file.sha256}")
Copying, moving, and linking
var source = File("original.txt")
source.copy("backup.txt")
source.move("archive/original.txt")
File("data.txt").link("hardlink.txt")
File("data.txt").symlink("symlink.txt")
In-place, line-by-line editing
# Uppercase every line
File("text.txt").edit {|line| line.uc }
# Replace a pattern on every line
File("config.ini").edit {|line| line.gsub(/old_value/, "new_value") }
Working with file handles
var fh = File("large.txt").open_r
fh.each_line {|line| say(line.trim) }
fh.close
var out = File("output.txt").open_w
out.say("Header")
10.times {|i| out.say("Line #{i}") }
out.close
Temporary files
var tmp = File.mktemp
tmp.say("temporary data")
tmp.close
File type checking
var path = File(ARGV[0])
given (path) {
when { .is_file } { say("Regular file") }
when { .is_dir } { say("Directory") }
when { .is_link } { say("Symbolic link -> #{path.readlink}") }
when { .is_socket } { say("Unix socket") }
default { say("Unknown file type") }
}
SEE ALSO
Sidef::Types::Glob::Dir, Sidef::Types::Glob::FileHandle, Sidef::Types::String::String