重定向

  1. (let ((*standard-output* <some form generating a stream>))
  2. ...)

由于 *STANDARD-OUTPUT* 是个动态变量,所以执行是需要用 let 来绑定。在 LET 中,*STANDARD-OUTPUT* 之前的变量会保存下来,不论之前的值是什么。
如果要将一个程序的输出写入到一个文件中,可以使用如下格式:

  1. (with-open-file (*standard-output* "somefile.dat" :direction :output
  2. :if-exists :supersede)
  3. ...)
  4. )

WITH-OPEN-FILE 将会打开一个文件(如果文件不存在就创建该文件),然后执行程序主体,将输出的结果写入到文件中,然后恢复原来 *STANDARD-OUTPUT*的值。

打印字符流

所谓的打印字符流就是将编码为0-255(8位,1字节)所表示的字符打印出来。

CLISP

  1. :external-format
  2. (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) 这样的字符:

  1. ;*** - Character #\u0080 cannot be represented in the character set CHARSET:CP1252

ASCII 无法显示编码大于 127 的字符。

  1. ;*** - 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 确认过。

例子:

  1. (defvar *unicode-test-file* "faithtest-out.txt")
  2. (defun generate-256 (&key (filename *unicode-test-file*)
  3. #+CLISP (charset 'charset:iso-8859-1)
  4. external-format)
  5. (let ((e (or external-format
  6. #+CLISP (ext:make-encoding :charset charset :line-terminator :unix))))
  7. (describe e)
  8. (with-open-file (f filename :direction :output
  9. :external-format e)
  10. (write-sequence
  11. (loop with s = (make-string 256)
  12. for i from 0 to 255
  13. do (setf (char s i) (code-char i))
  14. finally (return s))
  15. f)
  16. (file-position f))))
  17. ;(generate-256 :external-format :default)
  18. ;#+CLISP (generate-256 :external-format :unix)
  19. ;#+CLISP (generate-256 :external-format 'charset:ascii)
  20. ;(generate-256)
  21. (defun check-256 (&optional (filename *unicode-test-file*))
  22. (with-open-file (f filename :direction :input
  23. :element-type '(unsigned-byte 8))
  24. (loop for i from 0
  25. for c = (read-byte f nil nil)
  26. while c
  27. unless (= c i)
  28. do (format t "~&Position ~D found ~D(#x~X)." i c c)
  29. when (and (= i 33) (= c 32))
  30. do (let ((c (read-byte f)))
  31. (format t "~&Resync back 1 byte ~D(#x~X) - cause CRLF?." c c) ))
  32. (file-length f)))
  33. #| CLISP
  34. (check-256 *unicode-test-file*)
  35. (progn (generate-256 :external-format :unix) (check-256))
  36. ; uses UTF-8 -> 385 bytes
  37. (progn (generate-256 :charset 'charset:iso-8859-1) (check-256))
  38. (progn (generate-256 :external-format :default) (check-256))
  39. ; uses UTF-8 + CRLF(on MS-Windows) -> 387 bytes
  40. (progn (generate-256 :external-format
  41. (ext:make-encoding :charset 'charset:iso-8859-1 :line-terminator :mac)) (check-256))
  42. (progn (generate-256 :external-format
  43. (ext:make-encoding :charset 'charset:iso-8859-1 :line-terminator :dos)) (check-256))
  44. | #

快速批量输入输出

当需要同时在源和目标流中拷贝大量的数据时,可以使用 READ-SEQUENCEWRITE-SEQUENCE

  1. (let ((buf (make-array 4096 :element-type (stream-element-type input-stream))))
  2. (loop for pos = (read-sequence buf input-stream)
  3. while (plusp pos)
  4. do (write-sequence buf output-stream :end pos)))