Ruby programs use a structured exception handling mechanism built around the begin, rescue, and ensure keywords. Risky code is wrapped in a begin block, and any raised exception that matches a rescue clause can be caught and handled, often bound to a variable such as e for inspection. The most common pattern catches StandardError, the default superclass for application-level errors, and either logs the message, re-raises the exception, or attempts recovery.
The ensure clause, when present, runs whether or not an exception was raised, making it ideal for cleanup tasks like closing files, releasing locks, or restoring state. This guarantees that resources do not leak even when something goes wrong mid-operation. Programmers can also define custom exception classes simply by subclassing StandardError and then raise them with the raise keyword, passing an instance of the custom class along with a descriptive message. Such custom errors are then caught with rescue MyError => e in the same way built-in exceptions are.
File input and output in Ruby is straightforward through the File class. The simplest way to read a file is to call File.read with a path, which returns the entire contents as a string. For line-by-line processing, File.foreach iterates through the file without loading it all at once, which is more memory-efficient for large files. Using File.open with a block automatically closes the file when the block exits, so the idiom of passing a block to File.open is preferred. Writing to a file uses File.open with the "w" mode to overwrite or "a" mode to append, with methods like puts writing strings followed by a newline.