Working with Files
Prerequisites: Exceptions in depth, Blocks
Ruby's File class reads and writes files with a few short methods.
Writing and reading a whole file
File.write("notes.txt", "First line\nSecond line\n")
content = File.read("notes.txt")
puts content
p File.exist?("notes.txt")
p File.readlines("notes.txt").length
First line
Second line
true
2
File.write replaces the file's contents. To add to the end
instead, pass mode: "a" (append):
File.write("notes.txt", "Third line\n", mode: "a").
Reading line by line
File.read loads the entire file into memory. For large files, read
one line at a time with File.foreach:
File.write("scores.txt", "ada,90\nlinus,75\ngrace,88\n")
File.foreach("scores.txt") do |line|
name, score = line.chomp.split(",")
puts "#{name.capitalize}: #{score}"
end
p File.readlines("scores.txt", chomp: true)
Ada: 90
Linus: 75
Grace: 88
["ada,90", "linus,75", "grace,88"]
File.open with a block
For more control, open the file with a block. Ruby closes the file automatically when the block ends — even if an error is raised inside it:
File.open("log.txt", "w") do |file|
file.puts "Started"
file.puts "Finished"
end
puts File.read("log.txt")
Started
Finished
Common modes: "r" read (default), "w" write (replace), "a"
append.
Paths and folders
require "fileutils"
FileUtils.mkdir_p("reports/2025")
File.write(File.join("reports", "2025", "jan.txt"), "data")
p Dir.glob("reports/**/*.txt")
p File.basename("reports/2025/jan.txt", ".txt")
p File.extname("photo.jpeg")
FileUtils.rm_rf("reports")
["reports/2025/jan.txt"]
"jan"
".jpeg"
File.join builds paths with the right separator; Dir.glob finds
files by pattern (** means "any folder depth").
Common mistakes
- Reading a file that doesn't exist:
No such file or directory @ rb_sysopen - missing.txt (Errno::ENOENT). Check withFile.exist?or rescueErrno::ENOENT. - Opening a file with
File.openwithout a block and forgetting to callclose. - Relative paths are relative to where you ran the script, not to
where the script lives. Use
File.join(__dir__, "data.txt")for files next to the script.
Practice
Write a list of three shopping items to shopping.txt, one per line,
then read it back and print each item numbered (1. milk).
Show solution
File.write("shopping.txt", %w[milk eggs bread].join("\n"))
File.readlines("shopping.txt", chomp: true).each_with_index do |item, i|
puts "#{i + 1}. #{item}"
end