重定向
(let ((*standard-output* <some form generating a stream>))
...)
由于 *STANDARD-OUTPUT*
是个动态变量,所以执行是需要用 let 来绑定。在 LET
中,*STANDARD-OUTPUT*
之前的变量会保存下来,不论之前的值是什么。
如果要将一个程序的输出写入到一个文件中,可以使用如下格式:
(with-open-file (*standard-output* "somefile.dat" :direction :output
:if-exists :supersede)
...)
)
WITH-OPEN-FILE
将会打开一个文件(如果文件不存在就创建该文件),然后执行程序主体,将输出的结果写入到文件中,然后恢复原来 *STANDARD-OUTPUT*
的值。
打印字符流
所谓的打印字符流就是将编码为0-255(8位,1字节)所表示的字符打印出来。
CLISP
:external-format
(ext:make-encoding :charset 'charset:iso-8859-1 :line-terminator :unix)
同时也可以使用 (SETF (STREAM-ELEMENT-TYPE F) '(UNSIGNED-BYTE 8))
,因为 SETF
是 CLISP 中额外的拓展。使用 :EXTERNAL-FORMAT :UNIX
时会存在移植性的问题,因为 MS-Windows 的默认编码是 CHARSET:CP1252
,而 CHARSET:CP1252
不允许输出类似 (CODE-CHAR #x81)
这样的字符:
;*** - Character #\u0080 cannot be represented in the character set CHARSET:CP1252
ASCII 无法显示编码大于 127 的字符。
;*** - Character #\u0080 cannot be represented in the character setCHARSET:ASCII
CMUCL
:EXTERNAL-FORMATL :DEFAULT
,没有测试过,无unicode,也没可以使用
AllegroCL
#+(AND ALLEGRO UNIX) :DEFAULT
,也没测试过,Unix上应该可以使用,但是 MS-Windows 可能无法使用.
LispWorks
EXTERNAL-FORMAT '(:LATIN-1 :EOL-STYLE :LF)
,由 MArc Battyani 确认过。
例子:
(defvar *unicode-test-file* "faithtest-out.txt")
(defun generate-256 (&key (filename *unicode-test-file*)
#+CLISP (charset 'charset:iso-8859-1)
external-format)
(let ((e (or external-format
#+CLISP (ext:make-encoding :charset charset :line-terminator :unix))))
(describe e)
(with-open-file (f filename :direction :output
:external-format e)
(write-sequence
(loop with s = (make-string 256)
for i from 0 to 255
do (setf (char s i) (code-char i))
finally (return s))
f)
(file-position f))))
;(generate-256 :external-format :default)
;#+CLISP (generate-256 :external-format :unix)
;#+CLISP (generate-256 :external-format 'charset:ascii)
;(generate-256)
(defun check-256 (&optional (filename *unicode-test-file*))
(with-open-file (f filename :direction :input
:element-type '(unsigned-byte 8))
(loop for i from 0
for c = (read-byte f nil nil)
while c
unless (= c i)
do (format t "~&Position ~D found ~D(#x~X)." i c c)
when (and (= i 33) (= c 32))
do (let ((c (read-byte f)))
(format t "~&Resync back 1 byte ~D(#x~X) - cause CRLF?." c c) ))
(file-length f)))
#| CLISP
(check-256 *unicode-test-file*)
(progn (generate-256 :external-format :unix) (check-256))
; uses UTF-8 -> 385 bytes
(progn (generate-256 :charset 'charset:iso-8859-1) (check-256))
(progn (generate-256 :external-format :default) (check-256))
; uses UTF-8 + CRLF(on MS-Windows) -> 387 bytes
(progn (generate-256 :external-format
(ext:make-encoding :charset 'charset:iso-8859-1 :line-terminator :mac)) (check-256))
(progn (generate-256 :external-format
(ext:make-encoding :charset 'charset:iso-8859-1 :line-terminator :dos)) (check-256))
| #
快速批量输入输出
当需要同时在源和目标流中拷贝大量的数据时,可以使用 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)))