Ввод/Вывод
Перенаправление стандартного вывода
Вы можете сделать это так:
(let ((*standard-output* <some form generating a stream>))
...)
*standard-output* - динамическая переменная. То значение, которое она получит внутри окружения, создаваемого формой let, не повлияет на ее значение в глобальном окружении, и после выполнения формы let старое значение *standard-output* восстановится независимо от того, вышли ли мы из let нормально, через return-form, исключение или как-то еще. (Это, кстати, причина, по которой глобальные переменные в common lisp стабильнее, чем в других языках.)
Если вы хотите перенаправить вывод в файл, вы можете написать нечто вроде
(with-open-file (*standard-output* "somefile.dat" :direction :output
:if-exists :supersede)
...)
with-open-file - это удобный макрос, подробно рассмотренный в главе Файлы и директории. В данном примере *standard-output* связывается с файлом somefile.dat, выполняется тело макроса, файл закрывается и значение *standard-output* восстанавливается.
Faithful (корректный, точный?) output with Character Streams
Под точным выводом подразумевается, что символы с кодами от 0 до 255 будут выводится как есть. Это значит, что можно выполнить (PRINC (CODE-CHAR 0..255) s) в поток и ожидать вывода 8-битных байт, что не является очевидным во времена Unicode и 16- или 32-битных представлений символов. При этом не обязательно, чтобы символы ä, ß, или þ имели свои CHAR-CODE в диапазоне 0..255 - реализация может свободно использовать любой код. Тем не менее
Быстрый пакетный ввод/вывод
Если вам нужно скопировать сразу много данных, и как источник, так и получатель - потоки (или одного типа), то программа будет очень быстро работать с использованием функций read-sequence и write-sequence:
(let ((buf (make-array 4096 :element-type (stream-element-type input-stream))))
(loop for pos = (read-sequence buf input-stream)
while (plusp pos)
do (write-sequence buf output-stream :end pos)))
Например, ниже следующий код быстро отдает через веб-сервер hunchentoot очень большие файлы:
(with-open-file (input-stream "./out/log.txt" :element-type '(unsigned-byte 8))
(let ((output-stream (hunchentoot:send-headers))
(buf (make-array 4096 :element-type (stream-element-type input-stream))))
(loop for pos = (read-sequence buf input-stream)
while (plusp pos)
do (write-sequence buf output-stream :end pos))))
разумеется одать файл можно и более простым способом (hunchentoot:handle-static-file), но этот код может оказаться полезным, если необходимо отдавать много генерируемых на лету данных, (которые могут не поместиться в памяти)