All of the input and output functions described below (as well as many more) are built into the language.
To print output to the terminal, use the function format destination controlString, with the destination as t.
Just like most languages use escape characters, Lisp has directives, which are indicated by ~. There are powerful options even to print text based on a conditional built into the string.
To print just an object, use write. This is like using Java's toString method on an object.
The basic function for input is read. This reads from the current input stream, which is by default the terminal. Something to keep in mind when prompting for input is that the prompt may not get written out to the stream immediately (before waiting for input) unless you end it with a new line character (~%). You can also see in the following example another use of a directive. ~S formats expressions such as integers.
Similar functions provide ways to read different amounts of input, including read-char and read-line.
A special option is y-or-n-p, which requires the input to be a binary response. Different implementations accept different affirmative/negative replies, but "y" and "n" are typical.
Lisp handles file I/O with streams, which are opened with the function with-open-file. By default this creates an input stream, but you can specify an output or bidirectional stream as well.
There is a function open but it is not as safe as with-open-file since the latter will close the file in the case of an exception.
Keyword arguments allow you to specify options such as whether you will handle characters or bytes, whether you are reading or writing, and what to do in the case that a file does or does not exist.
The last are sort of like built-in exception handling where you can choose from a finite number of options for handling. Options include renaming, overwriting, or appending for existence, and creating a new file or doing nothing for non-existence. The default behavior is to throw an error.