Scripting and data jobs, one of Ruby's strengths, are mostly reading, transforming and writing files.
The simplest file operations are one-liners: File.read(path) returns the whole content, File.write(path, text) replaces it, and File.readlines(path, chomp: true) returns an array of lines. They are fine for small files.
For anything larger or longer-lived, use the block form of File.open, which closes the file even if an exception is raised:
File.open("out.log", "a") { |f| f.puts "started" }Modes: "r" read (default), "w" truncate and write, "a" append, "r+" read and write; add "b" for binary. File.foreach(path) { |line| ... } streams a file line by line in constant memory.
Paths: File.join("data", "x.csv"), File.exist?, File.basename, File.extname, Dir.glob("logs/**/*.log"), and Pathname for an object-oriented API. __dir__ is the directory of the current file, useful for locating data next to a script.
Standard library helpers you will use constantly:
require "json":JSON.parse(text, symbolize_names: true)andobj.to_jsonorJSON.pretty_generate(obj).require "csv":CSV.foreach(path, headers: true) { |row| row["email"] }. Since Ruby 3.4 csv is a bundled gem, so add it to your Gemfile in Bundler projects.require "fileutils":mkdir_p,cp,rm_rf.
Standard streams are $stdin, $stdout and $stderr; warn "msg" writes to stderr, and ARGV holds command-line arguments.
Example
require "json"
require "tmpdir"
Dir.mktmpdir do |dir|
path = File.join(dir, "people.jsonl")
File.open(path, "w") do |f|
f.puts({ name: "Ada", langs: %w[ruby c] }.to_json)
f.puts({ name: "Bo", langs: %w[go] }.to_json)
end
people = File.foreach(path).map { JSON.parse(it, symbolize_names: true) }
p people.first # {name: "Ada", langs: ["ruby", "c"]}
p people.sum { it[:langs].size } # 3
File.write(File.join(dir, "summary.json"), JSON.pretty_generate(people))
p Dir.glob("#{dir}/*").map { File.basename(it) }.sort
# ["people.jsonl", "summary.json"]
p File.extname(path) # ".jsonl"
endRemember
- Use File.open with a block so files are always closed
- File.foreach streams large files line by line
- JSON.parse(text, symbolize_names: true) gives symbol keys
Watch out for
- Calling File.open without a block and forgetting to close the file.