Clozure CL中文版014:流
Category:帮助手册流
流扩展
流外部格式
stream-external-format可以应用于(并且可以返回非空结果)不是FILE-STREAMs的开放流。
(setf stream-external-format)可用于更改用open或创建的开放流的外部格式make-socket。
OPEN和MAKE-SOCKET的其他关键字
open并 make-socket已分别被扩展,以附加的关键字参数::CLASS,:SHARING,和 :BASIC。
:CLASS
用于命名所需流类的符号。指定的类必须从FILE-STREAMfor 继承 open。
:SHARING
指定多个线程如何使用流。可能的值是: :PRIVATE,:LOCK和 :EXTERNAL。:PRIVATE是默认值。 NIL也被接受作为的同义词:EXTERNAL。
:PRIVATE
指定只能由首先尝试对其执行I / O的线程访问该流; 该线程成为流的“所有者”,并且不一定是与创建流的线程相同的线程。这是默认值。(有关openmcl-devel关于流转移所有权的想法的一些讨论;这尚未实现。)尝试在流上执行I / O:从流的所有者以外的线程进行PRIVATE共享产生错误。
:LOCK
指定对流的所有访问都需要调用线程获取锁。IO流有单独的“读”和“写”锁。这使得例如一个线程可以从这样的流中读取而另一个线程写入它。(另见)make-read-write-lockwith-read-lockwith-write-lock
:EXTERNAL
指定I / O原语不强制执行访问协议。这可能适用于某些类型的应用程序,它们可以通过应用程序级协议控制流访问。请注意,由于即使从流中读取的操作也会更改其内部状态(并且因此来自多个线程的同时访问可能导致该状态的损坏),因此必须在设计此类协议时采取一些措施。
:BASIC
一个布尔值,表示该流是否是一个格雷流,即是否该流的一个实例FUNDAMENTAL-STREAM或 CCL::BASIC-STREAM(参见基本对战基本流)。默认为 T。
基本与基础流
灰色流(请参阅使用灰色流创建自己的流类)都继承自FUNDAMENTAL-STREAM基本流继承自CCL::BASIC-STREAM。FUNDAMENTAL和BASIC流之间的权衡完全在灵活性和性能,潜在或实际之间。I / O原语可以识别BASIC-STREAM并利用实现细节的知识。基础流类可以以标准方式(灰色流协议)进行子类化和扩展。
对于现有的流类(FILE-STREAM,SOCKET和用于实现文件流和套接字的内部CCL :: FD-STREAM类),可以在FUNDAMENTAL和BASIC实现之间共享许多代码。最大的区别应该是可以从像READ-CHAR这样的I / O原语到达代码,而无需通过一些支持通用性和可扩展性的步骤,并且当不需要支持时跳过这些步骤可以提高I / O O表现。
Gray stream方法 stream-read-char应该适用于 BASIC-STREAMs。(可能仍然存在这样的方法未定义的情况;这种情况应该被视为错误。)不能保证I / O原语可以调用Gray流方法从a读取字符BASIC-STREAM,尽管仍然存在这样的情况:有时候是这样的。
从文本文件中读取2M个字符的简单循环在打开新默认值时(:SHARING :PRIVATE :BASIC T)比运行这些更改之前快10倍。这听起来不错,直到有人意识到“等效”C循环仍然快了大约10倍……
流超时和截止日期
即与文件描述符相关联的流具有的属性和访问器: stream-input-timeout,stream-output-timeout,和 stream-deadline。所有三个访问器都有相应的setf方法。 stream-input-timeout并 stream-output-timeout以秒为单位指定,可以是小于一百万的任何正实数。设置超时并且相应的I / O操作所需的时间超过指定的时间间隔时,将发出错误信号。INPUT-TIMEOUT输入和 OUTPUT-TIMEOUT输出错误。 STREAM-DEADLINE以内部时间单位指定绝对时间。如果流上的I / O操作未在截止时间之前完成,则a COMMUNICATION-DEADLINE-EXPIRED发出错误信号。截止日期优先于可设置的任何输入/输出超时。
打开文件流
Clozure CL维护一个打开的文件流列表。这有助于确保在lisp退出时以有序的方式关闭流。以下线程安全功能管理此列表。
open-file-streams[功能]
返回当前打开的文件流的新列表。
note-open-file-stream file-stream[功能]
将文件流添加到返回的打开文件流的内部列表中open-file-streams。此功能是线程安全的。它通常只在创建文件流时从自定义流代码中调用。
remove-open-file-stream file-stream[功能]
从返回的打开文件流的内部列表中删除文件流open-file-streams。此功能是线程安全的。它通常只在文件流关闭时从自定义流代码中调用。
使用灰色流创建自己的流类
概观
本节仍在编写和修订,因为它非常不完整。字典部分目前仅列出几个函数。警告讲师。
灰色流是Common Lisp的扩展。几年前,他们被大卫·格雷(精明的读者现在理解他们的名字)提议标准化,但不被接受,因为他们没有经过充分的尝试来发现他们的概念问题。
从那以后,它们已经被很多现代的Lisp实现实现了。但是,它们的确存在一些不足之处,每种实施方式都以不同的方式解决了这些问题。今天的情况是,甚至很难找到如何开始使用Gray流。这就是标准很重要的原因。
以下是您希望新流类继承的一些类的列表:
基本流基本输入流基本输出流基本字符流基本二进制流基本字符输入流基本字符输出流基本二进制输入流基本二进制输出stream ccl :: buffered-stream-mixin ccl :: buffered-input-stream-mixin ccl :: buffered-output-stream-mixin ccl :: buffered-io-stream-mixin ccl :: buffered-character-input-stream- mixin ccl :: buffered-character-output-stream-mixin ccl :: buffered-character-io-stream-mixin ccl :: buffered-binary-input-stream-mixin ccl :: buffered-binary-output-stream-mixin ccl :: buffered-binary-io-stream-mixin file-stream file-input-stream file-output-stream file-io-stream file-character-input-stream file-character-output-stream file-character-io-stream file-binary-input-stream file-binary-output-stream file-binary-io-stream ccl ::fd-stream ccl :: fd-input-stream ccl :: fd-output-stream ccl :: fd-io-stream ccl :: fd-character-input-stream ccl :: fd-character-output-stream ccl :: fd-character-io-stream ccl :: fd-binary-input-stream ccl :: fd-binary-output-stream ccl :: fd-binary-io-stream
所有这些都在ccl / level-1 / l1-streams.lisp中定义,除了ccl:file- *之外,它们位于ccl / level-1 / l1-sysio.lisp中。
根据最初的Gray stream提议,您应该继承最适用的基本*类。但是,使用Clozure CL,如果你想要缓冲以获得更好的性能,除非你知道某些原因你不会这样做,否则你应该从相应的ccl :: buffered- *类继承你这样的缓冲与在普通的非灰色流上使用的缓冲完全相同,并且力输出将在其上正常工作。
请注意所有ccl :: buffered- *类的名称中的-mixin后缀?后缀意味着这个类本身并不“完整”; 即使你还从* -mixin流继承,你仍然需要从基本*流继承。您可以考虑像这样制作自己的课程。….除了他们确实继承了基本的*流,这很奇怪。
如果您希望能够使用:open参数(open)和(with-open-file)创建类的实例,则应该使其继承自file- *类之一。如果你这样做,没有必要继承任何其他类(虽然它不会伤害任何东西),因为file- *类已经做到了。
从file- *类继承时,可以在任何方法中使用(call-next-method)来获取标准行为。如果要创建执行某些简单过滤操作的类(例如将所有内容更改为大写或更改为不同的字符编码),这将非常有用。如果你这样做,你肯定需要专门化ccl :: select-stream-class。你在ccl :: stream-select-class上的方法应该接受类的一个实例,但不要注意它的内容,并返回一个符号,指定实际实例化的类。
如果你需要在所有不同类型的流中使你的功能通用,那么实现它的最好方法可能是使它成为一个混合,用输入,输出,io,字符和二进制的所有变体定义类,继承从你的mixin和相应的其他类中,然后在ccl :: select-stream-class上定义一个从这些类中选择的方法。
请注意,其中一些类是CCL包的内部类。如果你尝试从没有ccl ::前缀的那些继承,你会得到一个可能让你困惑的错误,称它们为“前向引用的类”。这只是意味着你使用了错误的符号,所以添加前缀。
下面是一些通用函数的列表,您可能希望专门用于新的流类,并且应该在某些时候记录这些函数。
stream-direction stream => stream-device stream direction => stream-length stream &optionalnew => stream-position stream &optionalnew => streamp stream => boolean stream-write-char output-stream char => stream-write-whole-string output-stream string => stream-read-char input-stream => stream-unread-char input-stream char => stream-force-output output-stream => nil stream-maybe-force-output output-stream => nil stream-finish-output output-stream => nil stream-clear-output output-stream => nil close stream &keyabort => boolean stream-fresh-line stream => t stream-line-length stream => length interactive-stream -p stream => boolean stream-clear-input input-stream => nil stream-listen input-stream => boolean stream-filename stream => string ccl :: select-stream-class instance in -p out -p char -p => class
以下函数是Common Lisp的标准部分,但在格雷流方面表现得特殊。
open-stream-p stream => generalized-boolean input-stream -p stream => generalized-boolean output-stream -p stream => generalized-boolean stream-element-type stream => stream-error-stream => open close与开档
具体来说,(open)和(with-open-file)接受一个新的关键字参数:class,它可以是一个命名类的符号; 班级本身; 或它的一个实例。这样给出的类必须是’stream的子类型,并且没有特定内容的它的实例将被传递给ccl :: select-stream-class以确定实际实例化的类。
以下是标准的,并不特别针对格雷流,但可能应该。
流外部的格式
扩展READ-SEQUENCE和WRITE-SEQUENCE
概观
“Gray Streams”API基于ANSI CL采用READ-SEQUENCE和WRITE-SEQUENCE函数之前的非正式提议。因此,Gray流类的作者没有“标准”方法通过利用流的内部知识(例如,它使用的缓冲机制)来提高这些功能的性能。
在没有任何这样的知识的情况下,READ-SEQUENCE和WRITE-SEQUENCE实际上只是一个方便的简写,适用于调用READ-CHAR / READ-BYTE / WRITE-CHAR / WRITE-BYTE的循环。下面描述的机制允许FUNDAMENTAL-STREAM的子类定义更专业(并且可能更有效)的行为。
笔记
READ-SEQUENCE和WRITE-SEQUENCE在调度到上述方法之一之前会对其参数进行一定程度的完整性检查和规范化。如果单个方法不能做任何特别聪明的事情,可以使用CALL-NEXT-METHOD来处理一般情况。
例
(defclass my-string-input-stream (fundamental-character-input-stream)
((string :initarg :string :accessor my-string-input-stream-string)
(index :initform 0 :accessor my-string-input-stream-index)
(length)))
(defmethod stream-read-vector ((stream my-string-input-stream) vector start end)
(if (not (typep vector ‘simple-base-string))
(call-next-method)
(with-slots (string index length)
(do* ((outpos start (1+ outpos)))
((or (= outpos end)
(= index length))
outpos))
(setf (schar vector outpos)
(schar string index))
(incf index)))))
多字节I / O.
Clozure CL中所有不能包含指向lisp对象的指针的堆分配对象表示为 ivectors。Clozure CL提供低级功能,并有效地在缓冲流和ivectors之间传输数据。这里描述的函数与ANSI CL READ-SEQUENCE和WRITE-SEQUENCE函数之间在功能上有一些重叠。
这里使用的术语“八位字节”意味着与术语“8位字节”大致相同。下面描述的函数在缓冲流和ivector之间传输指定的八位字节序列,并不真正关心更高级别的问题(比如该八位字节序列是否在边界内或者它与ivector的逻辑内容之间的关系)。)由于这些原因,这些功能通常不如ANSI对应的安全性和灵活性。
灰色流词典
stream-read-list stream list count[通用功能]
应该尝试读取将流中的元素计数到列表中,返回实际读取的元素数(如果文件过早结束,则可能小于计数。)
流
流,可能是一个基本输入流。
名单
一个列表。当READ-SEQUENCE调用STREAM-READ-LIST方法时,该参数保证是正确的列表。
计数
一个非负整数。当READ-SEQUENCE调用STREAM-READ-LIST方法时,保证该参数不大于列表的长度。
stream-write-list stream list count[通用功能]
写第一计数的元素列表来 流。忽略此方法的返回值。
流
流,可能是基本输出流。
名单
一个列表。当WRITE-SEQUENCE调用STREAM-WRITE-LIST方法时,该参数保证是正确的列表。
计数
一个非负整数。当WRITE-SEQUENCE调用STREAM-WRITE-LIST方法时,保证该参数不大于列表的长度。
stream-read-vector stream vector start end[通用功能]
读取来自流连续元素成矢量,开始于元素开始(含),并通过元件持续端(排他的。)应该返回向量元素的索引超出最后一个存储,其可以是小于端过早结束的情况下-of文件。
流
流,可能是一个基本输入流
向量
一个向量。当调用STREAM-READ-VECTOR方法时read-sequence,该参数保证是一个简单的一维数组。
开始
一个非负整数。当READ-SEQUENCE调用STREAM-READ-VECTOR方法时,该参数保证不大于end且不大于vector的长度。
结束
一个非负整数。当READ-SEQUENCE调用STREAM-READ-VECTOR方法时,该参数保证不小于end并且不大于vector的长度。
stream-write-vector stream vector start end[通用功能]
应该尝试写的连续元素向量到流,开始于元素开始(含),并通过元件持续 端(排他的。)
流
流,可能是基本输出流
向量
一个向量。当WRITE-SEQUENCE调用STREAM-WRITE-VECTOR方法时,该参数保证是一个简单的一维数组。
开始
一个非负整数。当WRITE-SEQUENCE调用STREAM-WRITE-VECTOR方法时,该参数保证不大于end并且不大于vector的长度。
结束
一个非负整数。当WRITE-SEQUENCE调用STREAM-WRITE-VECTOR方法时,该参数保证不小于end且不大于vector的长度。
ccl::stream-device s direction[通用功能]
返回与给定lisp流关联的OS文件描述符。
stream-device (s stream) direction => fd
小号
一条小溪。
方向
或者:INPUT或:OUTPUT。
FD
文件描述符,是操作系统用来指代打开文件,套接字或类似I / O连接的非负整数。如果在方向给定的 方向上没有与s关联的文件描述符,则为NIL。
返回与相关的文件描述符 小号中给出的方向 方向。由于输入和输出文件描述符可能不同,因此必须指定 方向 ; 最常见的情况是其中一个被Unix shell重定向。
stream-read-ivector stream ivector start-octet max-octets[Generic Function]
从流到ivector读取最大八位字节八位字节,将它们存储在start-octet。返回实际读取的八位字节数。
流
输入流。在BUFFERED-INPUT-STREAM上定义的方法要求流的元素类型的实例的八位字节大小为1。
ivector
任何ivector。
启动八位
非负整数。
MAX-个字节
非负整数。如果遇到EOF,则返回值可能小于此参数的值。
stream-write-ivector stream ivector start-octet max-octets[Generic Function]
从start-octet开始,将最大八位字节八位字节写入来自ivector的流。返回最大八位字节。
流
输入流。在BUFFERED-OUTPUT-STREAM上定义的方法要求流的元素类型的实例的八位字节大小为1。
ivector
任何ivector
启动八位
非负整数。
MAX-八位
非负整数。
;;; Write the contents of a (SIMPLE-ARRAY(UNSIGNED-BYTE 16) 3)
;;; to a character file stream. Read back the characters.
(let* ((a (make-array 3
:element-type ‘(unsigned-byte 16)
:initial-contents ‘(26725 27756 28449))))
(with-open-file (s “junk”
:element-type ‘character
:direction :io
:if-does-not-exist :create
:if-exists :supersede)
;; Write six octets (three elements).
(stream-write-ivector s a 0 6)
;; Rewind, then read a line
(file-position s 0)
(read-line s)))
;;; Write a vector of DOUBLE-FLOATs. Note that (to maintain
;;; alignment) there are 4 octets of padding before the 0th
;;; element of a (VECTOR DOUBLE-FLOAT) on 32-bit platforms.
;;; (Note that (= (- target::misc-dfloat-offset
;;; target::misc-data-offset) 4))
(defun write-double-float-vector
(stream vector &key (start 0) (end (length vector)))
(check-type vector (vector double-float))
(let* ((start-octet (+ (* start 8)
(- target::misc-dfloat-offset
target::misc-data-offset)))
(num-octets (* 8 (- end start))))
(stream-write-ivector stream vector start-octet num-octets)))
Lisp标准流和OS标准流
在正常的交互式使用中,双向流的输入和输出端*terminal-io*连接到操作系统的标准输入和标准输出。lisp流*standard-input*,*standard-output*和,*error-output*是同义词流*terminal-io*。
在批处理模式下,此布置略有修改。口齿不清流*standard-input*,*standard-output*和 *standard-error*直接对应于操作系统的标准输入,标准输出,和标准误差。如果lisp可以确定它可以访问操作系统tty,那么*terminal-io*它将被连接到那个。否则,输入和输出流*terminal-io* 将对应于操作系统的标准输入和标准输出。
http://mip.i3geek.com