Ruby File I/O
Ruby File I/O and Directories
Section titled “Ruby File I/O and Directories”Ruby provides a comprehensive set of I/O (Input/Output) related methods, primarily through the IO class and its subclasses like File. Many basic I/O operations are also available as methods in the Kernel module, making them globally accessible.
The IO class offers fundamental methods such as read, write, gets, puts, readline, getc, and printf. This chapter covers basic I/O functions and file/directory manipulation in Ruby.
Standard Input/Output
Section titled “Standard Input/Output”The puts Statement
Section titled “The puts Statement”puts (put string) writes its arguments to the standard output (STDOUT), each followed by a newline character. If an argument is an array, it writes each element on a new line. If called without arguments, it just prints a newline.
#!/usr/bin/env ruby# frozen_string_literal: true
val1 = "This is variable one"val2 = "This is variable two"puts val1puts val2puts [1, 2, 3] # Prints each number on a new lineThis produces:
This is variable oneThis is variable two123The gets Statement
Section titled “The gets Statement”gets (get string) reads a line of input from the standard input (STDIN). It returns the line including the trailing newline character, or nil if end-of-file is reached. Use chomp to remove the newline.
#!/usr/bin/env ruby# frozen_string_literal: true
puts "Enter your name:"name = getsputs "Hello, #{name.chomp}! You entered: #{name.inspect}" # .chomp removes trailing newline
puts "Enter your age:"age_str = gets.chompif age_str age = age_str.to_i puts "You will be #{age + 5} in 5 years."else puts "No age entered."endExample interaction:
Enter your name:AliceHello, Alice! You entered: "Alice\n"Enter your age:30You will be 35 in 5 years.The putc Statement
Section titled “The putc Statement”putc (put character) writes a single character to standard output. If given a string, it writes the first character. If given an integer, it writes the character corresponding to that byte value.
#!/usr/bin/env ruby# frozen_string_literal: true
str = "Hello Ruby!"putc str # Outputs: Hputc 65 # Outputs: A (ASCII value for 'A')The print Statement
Section titled “The print Statement”print is similar to puts but does not automatically append a newline. It calls to_s on its arguments and writes them to STDOUT.
#!/usr/bin/env ruby# frozen_string_literal: true
print "Hello World"print " Good Morning"print "\nNext line."This produces:
Hello World Good MorningNext line.File Operations
Section titled “File Operations”Opening and Closing Files
Section titled “Opening and Closing Files”The File.open method is used to open a file. It can take a block, which is the recommended way as it ensures the file is automatically closed when the block finishes, even if errors occur.
# Syntax with a block (recommended)File.open("filename.txt", "mode") do |file_object| # ... process the file using file_object ...end # File is automatically closed here
# Syntax without a block (manual close needed)# aFile = File.new("filename.txt", "mode")# ... process the file ...# aFile.closeFile.new is similar to File.open but does not accept a block.
File Modes:
| Mode | Description |
|---|---|
| r | Read-only. Starts at the beginning of the file (default mode). |
| r+ | Read-write. Starts at the beginning of the file. |
| w | Write-only. Truncates existing file to zero length or creates a new file for writing. |
| w+ | Read-write. Truncates existing file or creates a new file for reading and writing. |
| a | Write-only (append). Starts at the end of the file if it exists, or creates a new file. Data is always written to the end. |
| a+ | Read-write (append). Starts at the end for writing. Reading can happen from any position. Creates a new file if it doesn’t exist. |
| b | Binary file mode (optional, can be combined with other modes e.g., “rb”, “wb+”). On some systems (like Windows), this influences newline handling. |
Reading and Writing Files
Section titled “Reading and Writing Files”Once a file is open, you can use IO methods like read, gets, puts, write on the file object.
The sysread and syswrite Methods (Low-Level):
Section titled “The sysread and syswrite Methods (Low-Level):”sysread reads a specified number of bytes from the file directly from the OS buffer, bypassing Ruby’s internal buffering. syswrite does the same for writing. These are less common than buffered I/O methods.
#!/usr/bin/env ruby# frozen_string_literal: true
# Create a sample fileFile.open("sample.txt", "w") { |f| f.puts "This is line one."; f.puts "This is line two." }
# Using sysreadbegin File.open("sample.txt", "r") do |file| content_chunk = file.sysread(20) # Read up to 20 bytes puts "First 20 bytes (sysread): #{content_chunk.inspect}" endrescue EOFError puts "sysread: End of file reached prematurely."end
# Using syswrite (overwrites beginning of file)begin File.open("sample.txt", "r+") do |file| bytes_written = file.syswrite("HELLO ") puts "Bytes written (syswrite): #{bytes_written}" endrescue SystemCallError => e puts "syswrite error: #{e.message}"end
# Check content after syswriteputs "Content after syswrite: #{File.read('sample.txt').inspect}"The each_byte Method:
Section titled “The each_byte Method:”Iterates over each byte of the file (as an integer).
#!/usr/bin/env rubyFile.open("sample.txt", "r") do |file| puts "Bytes in sample.txt:" file.each_byte { |byte| print "#{byte.chr}." if byte < 128 } # Print printable ASCII chars putsendThe IO.readlines and File.readlines Methods:
Section titled “The IO.readlines and File.readlines Methods:”Reads the entire file into an array of strings, where each element is a line from the file (including newlines). Use with caution for very large files as it loads everything into memory.
#!/usr/bin/env ruby# frozen_string_literal: true
begin lines_array = File.readlines("sample.txt") # IO.readlines is similar puts "Line 0: #{lines_array[0].chomp if lines_array[0]}" puts "Line 1: #{lines_array[1].chomp if lines_array[1]}"rescue Errno::ENOENT puts "File not found."endThe IO.foreach and File.foreach Methods:
Section titled “The IO.foreach and File.foreach Methods:”Iterates over each line of the file, passing it to a block. More memory-efficient for large files than readlines as it processes line by line.
#!/usr/bin/env ruby# frozen_string_literal: true
begin File.foreach("sample.txt") do |line| puts "Processing line: #{line.chomp}" endrescue Errno::ENOENT puts "File not found."endOther common reading methods: File.read(filename) reads the entire file content into a single string. file.read(length) reads length bytes.
Renaming and Deleting Files
Section titled “Renaming and Deleting Files”File.rename(old_name, new_name) renames a file.
File.delete(filename) or File.unlink(filename) deletes a file.
#!/usr/bin/env ruby# Create a file to work withFile.write("original.txt", "Some content.")
# Rename the fileif File.exist?("original.txt") File.rename("original.txt", "renamed.txt") puts "original.txt renamed to renamed.txt"end
# Delete the fileif File.exist?("renamed.txt") File.delete("renamed.txt") puts "renamed.txt deleted"endFile Modes and Ownership (Permissions)
Section titled “File Modes and Ownership (Permissions)”Use File.chmod(mode, filename, ...) to change the permissions (mode) of one or more files. The mode is an octal number.
#!/usr/bin/env rubyFile.write("script.sh", "#!/bin/bash\necho Hello")# Make it executable by owner, readable by owner/group/othersFile.chmod(0755, "script.sh")puts "Permissions for script.sh changed."# File.delete("script.sh") # CleanupCommon octal permission masks:
| Mask | Description (Permissions) |
|---|---|
| 0700 | rwx------ (Owner: read, write, execute) |
| 0600 | rw------- (Owner: read, write) |
| 0755 | rwxr-xr-x (Owner: rwx; Group: rx; Others: rx) - Common for executables/directories |
| 0644 | rw-r—r— (Owner: rw; Group: r; Others: r) - Common for regular files |
File Inquiries (Predicates)
Section titled “File Inquiries (Predicates)”Ruby provides many methods to query file attributes (often ending with ?):
#!/usr/bin/env ruby# frozen_string_literal: truefilename = "sample.txt"File.write(filename, "Test content for inquiries.") unless File.exist?(filename)
puts "File '#{filename}' exists? #{File.exist?(filename)}" # => trueputs "Is it a file? #{File.file?(filename)}" # => trueputs "Is it a directory? #{File.directory?(filename)}" # => falseputs "Is it readable? #{File.readable?(filename)}" # => true (usually)puts "Is it writable? #{File.writable?(filename)}" # => true (usually)puts "Is it executable? #{File.executable?(filename)}" # => false (for a text file usually)puts "Is it zero size? #{File.zero?(filename)}" # => false (if it has content)puts "Size: #{File.size(filename)} bytes" # => (size of content)puts "Size (or nil if zero): #{File.size?(filename)} bytes" # => (size of content, or nil if zero)puts "File type: #{File.ftype(filename)}" # => "file"puts "Created time: #{File.ctime(filename)}"puts "Modified time: #{File.mtime(filename)}"puts "Last accessed time: #{File.atime(filename)}"
# File.delete(filename) # CleanupThe ftype method can return: file, directory, characterSpecial, blockSpecial, fifo, link, socket, or unknown.
Directories in Ruby
Section titled “Directories in Ruby”The Dir class is used for directory operations.
Navigating and Listing Directories
Section titled “Navigating and Listing Directories”Dir.chdir(path): Changes the current working directory.
Dir.pwd: Returns the current working directory path.
Dir.entries(path): Returns an array of all entries (files and directories, including . and ..) in the specified path.
Dir.foreach(path) { |entry| ... }: Iterates over entries.
Dir.glob(pattern) or Dir[pattern]: Returns an array of filenames matching the pattern (wildcards like *, ?, []).
#!/usr/bin/env ruby# frozen_string_literal: true
puts "Current directory: #{Dir.pwd}"
# List entries in current directory (first 5 for brevity)puts "\nEntries in '.':"Dir.entries(".").first(5).each { |entry| puts " #{entry}" }
puts "\nRuby files in '.':"Dir.glob("*.rb").each { |file| puts " #{file}" }# Or: Dir["*.rb"].each { |file| puts " #{file}" }Creating and Deleting Directories
Section titled “Creating and Deleting Directories”Dir.mkdir(path, mode=0777): Creates a directory. mode specifies permissions.
Dir.delete(path) or Dir.rmdir(path) or Dir.unlink(path): Deletes an empty directory.
#!/usr/bin/env ruby# frozen_string_literal: true
dir_name = "mynewdir"
begin unless Dir.exist?(dir_name) Dir.mkdir(dir_name, 0755) puts "Directory '#{dir_name}' created." else puts "Directory '#{dir_name}' already exists." end
# ... do something with the directory ...
if Dir.exist?(dir_name) Dir.delete(dir_name) puts "Directory '#{dir_name}' deleted." endrescue SystemCallError => e puts "Directory operation failed: #{e.message}"endTemporary Files and Directories
Section titled “Temporary Files and Directories”For temporary files, Ruby’s standard library tmpdir and tempfile are useful.
#!/usr/bin/env ruby# frozen_string_literal: true
require 'tmpdir' # For Dir.tmpdirrequire 'tempfile' # For Tempfile class
# Using Dir.tmpdir (less common for direct file creation)temp_dir_path = Dir.tmpdircustom_temp_filename = File.join(temp_dir_path, "my_app_temp_#{Process.pid}.dat")puts "Custom temp file might be at: #{custom_temp_filename}"# Manual creation and deletion needed if using this approach directly.
# Using Tempfile (recommended for temporary files)begin temp_file = Tempfile.new('app_data_prefix') # Creates a temp file with a unique name temp_file.puts "This is some temporary data." temp_file.puts "It will be automatically deleted when the object is finalized or closed."
puts "Tempfile path: #{temp_file.path}" temp_file.rewind # Go back to the beginning to read puts "Tempfile content: #{temp_file.read.chomp}"
ensure # Tempfile handles its own deletion upon garbage collection or explicit close and unlink temp_file.close # Closes the file temp_file.unlink # Deletes the file from the filesystem (optional, close often does it) puts "Tempfile closed and unlinked."endBuilt-in Functions for Files and Directories
Section titled “Built-in Functions for Files and Directories”Ruby’s File and Dir classes, along with methods in FileUtils (a standard library module require 'fileutils'), offer a rich API for all common file and directory manipulations. Consult the official Ruby documentation for a complete list of methods and their options.