IO::Handle
的实例封装一个句柄来操作输入/输出资源。通常无需直接创建 IO::Handle
实例,因为其他角色和方法会执行此操作。例如,IO::Path
对象提供一个 open 方法,该方法返回一个 IO::Handle
my = '/tmp/log.txt'.IO.open;say .^name; # OUTPUT: IO::Handle
第一行与以下代码段几乎等效
my = IO::Handle.new( :path( '/tmp/log.txt'.IO.path ) ).open;
方法§
方法 open§
method open(IO::Handle::, :, :, :, :,:, :, :,: is copy,: is copy,: is copy,: is copy,: is copy,:,: is copy,: = ,: is copy = ,Str : is copy = ,: is copy,)
在其中一种模式下打开句柄。如果打开失败,则 失败并引发适当的异常。
有关 :$chomp
、:$nl-in
、:$nl-out
和 :$enc
的接受值和行为,请参阅各个方法的说明。参数的默认值与调用者的属性相同,如果提供了其中任何一个,则属性将更新为新值。指定设置为 True
的 :$bin
而不是 :$enc
以指示应以二进制模式打开句柄。将未定义的值指定为 :$enc
等效于根本不指定 :$enc
。同时将定义的编码指定为 :$enc
和将 :$bin
设置为 true 将导致引发 X::IO::BinaryAndEncoding
异常。
打开模式默认为非独占、只读(与指定 :r
相同),并且可以通过以下参数的组合来控制
:r same as specifying :mode<ro> same as specifying nothing :w same as specifying :mode<wo>, :create, :truncate :a same as specifying :mode<wo>, :create, :append :x same as specifying :mode<wo>, :create, :exclusive :update same as specifying :mode<rw> :rw same as specifying :mode<rw>, :create :ra same as specifying :mode<rw>, :create, :append :rx same as specifying :mode<rw>, :create, :exclusive
参数 :r
与 :w
、:a
、:x
完全相同,与上表中最后三行所示的字母组合相同。对上述未列出的模式组合的支持取决于实现,应假定不受支持。也就是说,指定,例如,.open(:r :create)
或 .open(:mode<wo> :append :truncate)
可能有效,也可能导致宇宙内爆,具体取决于特定的实现。这也适用于以这种不受支持的模式打开的句柄的读/写操作。
模式详细信息如下
:mode<ro> means "read only" :mode<wo> means "write only" :mode<rw> means "read and write" :create means the file will be created, if it does not exist :truncate means the file will be emptied, if it exists :exclusive means .open will fail if the file already exists :append means writes will be done at the end of file's current contents
尝试打开目录、写入以只读模式打开的句柄或从以只写模式打开的句柄读取,或对以二进制模式打开的句柄使用文本读取方法将失败或引发异常。
在 6.c 语言中,可以打开路径 '-'
,这将导致 open
在只读模式下打开(如果 closed
)$*IN
句柄或在只写模式下打开 $*OUT
句柄。在这种情况下,所有其他模式都将导致引发异常。
从 6.d 语言版本开始,不赞成使用路径 '-'
,并且它将在未来的语言版本中完全删除。
:out-buffer
控制输出缓冲,默认情况下表现得好像它是 Nil
。有关详细信息,请参阅方法 out-buffer。
注意(2017.09 之前的 Rakudo 版本):文件句柄在超出范围时不会刷新或关闭。虽然它们将在垃圾回收时关闭,但不能保证会运行垃圾回收。这意味着你应该对为写入打开的句柄使用显式 close
,以避免数据丢失,并且还建议对为读取打开的句柄使用显式 close
,以便你的程序不会同时打开太多文件,从而在进一步的 open
调用中引发异常。
注意(Rakudo 版本 2017.09 及更高版本):打开的文件句柄将在程序退出时自动关闭,但仍然强烈建议你显式地 close
打开的句柄。
方法 comb§
method comb(IO::Handle: Bool :, |args --> Seq)
读取句柄并以与 Str.comb
相同的方式处理其内容,采用相同的参数,如果 $close
设置为真值,则在完成后关闭句柄。当调用此方法时,实现可能会完全吸收文件。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = 'path/to/file'.IO.open;say "The file has ♥s in it";
方法 chomp§
has is rw = True
可以通过 .new
或 open 设置的属性之一。默认为 True
。采用 Bool
,指定在使用 .get
或 .lines
方法时,是否应从内容中删除行分隔符(由 .nl-in
定义)。
routine get§
method get(IO::Handle: --> Str)multi get (IO::Handle = --> Str)
从句柄读取单行输入,如果句柄的 .chomp
属性设置为 True
,则删除尾随换行符(由 .nl-in
设置)。如果没有更多输入,则返回 Nil
。如果没有提供句柄,则子例程形式默认为 $*ARGFILES
。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
.get.say; # Read one line from the standard inputmy = open 'filename';.get.say; # Read one line from a file.close;say get; # Read one line from $*ARGFILES
routine getc§
method getc(IO::Handle: --> Str)multi getc (IO::Handle = --> Str)
从输入流读取单个字符。当句柄 处于二进制模式 时尝试调用此方法,将导致抛出 X::IO::BinaryMode
异常。如果没有提供句柄,则子例程形式默认为 $*ARGFILES
。如果没有更多输入,则返回 Nil
,否则操作将阻塞,等待至少一个字符可用;适用以下警告
Buffering terminals§
仅当您已将终端设置为“无缓冲”时,使用 getc 从终端获取单个按键才可正常工作。否则,终端将等待敲击回车键或填满缓冲区,然后编译器才能获取单个字节的数据。
Waiting for potential combiners§
如果句柄的编码允许读取组合字符,raku 将等待更多数据可用,然后再提供字符。这意味着输入一个“e”,后跟一个组合尖音符,将为您提供一个带尖音符的 e,而不是提供一个“e”,并让下一个读取函数为您提供一个悬空组合符。但是,这也意味着当用户只输入一个“e”,并且无意也输入一个组合尖音符时,您的程序将在返回初始“e”之前等待另一个按键。
submethod DESTROY§
submethod DESTROY(IO::Handle:)
关闭文件句柄,除非其 native-descriptor 为 2
或更低。这可确保不会无意中关闭标准文件句柄。
请注意,无法保证进行垃圾回收,因此您不得依赖 DESTROY
来关闭您写入的句柄,而应自行关闭。打开大量文件的程序也应显式关闭句柄,无论它们是否已打开以进行写入,因为在进行垃圾回收并关闭不再使用的句柄之前,可能会打开太多文件。
方法 gist§
method gist(IO::Handle: --> Str)
返回一个包含信息的字符串,其中包含 .path
(如果有的话)句柄创建的路径,以及它是否 .opened
。
say IO::Handle.new; # IO::Handle<(Any)>(closed)say "foo".IO.open; # IO::Handle<"foo".IO>(opened)
方法 eof§
method eof(IO::Handle: --> Bool)
非阻塞。如果读取操作已耗尽句柄的内容,则返回 True
。对于 可寻址 句柄,这意味着当前位置在文件末尾或文件末尾之后,并且 寻址 一个已耗尽的句柄返回到文件内容中将导致 eof 再次返回 False
。
对于 不可寻址 句柄和打开为零大小文件(包括 /proc/
中的特殊文件)的句柄,EOF 不会设置,直到读取操作无法读取任何字节。例如,在此代码中,第一个 read
消耗所有数据,但只有第二个 read
不读取任何内容,TTY 句柄上的 EOF 才会被设置
$ echo "x" | raku -e 'with $*IN { .read: 10000; .eof.say; .read: 10; .eof.say }'
False
True
方法 encoding§
multi method encoding(IO::Handle: --> Str)multi method encoding(IO::Handle: --> Str)
返回一个 Str
,表示句柄当前使用的编码,默认为 "utf8"
。 Nil
表示文件句柄当前处于二进制模式。指定可选的位置 $enc
参数会切换句柄使用的编码;指定 Nil
作为编码以将句柄置于二进制模式。
编码的接受值不区分大小写。可用的编码因实现和后端而异。在 Rakudo MoarVM 上支持以下内容
utf8 utf16 utf16le utf16be utf8-c8 iso-8859-1 windows-1251 windows-1252 windows-932 ascii
默认编码是 utf8,它会规范化为 Unicode NFC
(规范形式规范)。在某些情况下,您可能希望确保不进行规范化;为此,您可以使用 utf8-c8
。在使用 utf8-c8
之前,请阅读 Unicode:文件句柄和 I/O 以获取有关 utf8-c8
和 NFC
的更多信息。
从 Rakudo 2018.04 开始,还支持 windows-932,它是 ShiftJIS 的一个变体。
实现也可以选择提供对别名的支持,例如 Rakudo 允许别名 latin-1
编码为 iso-8859-1
和带破折号的 utf 版本:utf-8
和 utf-16
。
utf16、utf16le 和 utf16be§
与 utf8 不同,utf16 具有字节序——大端字节序或小端字节序。这与字节的顺序有关。计算机 CPU 也有字节序。Raku 的 utf16
格式说明符在编码时将使用主机系统的字节序。在解码时,它将查找字节顺序标记,如果存在,则使用它来设置字节序。如果没有字节顺序标记,它将假定文件使用与主机系统相同的字节顺序。字节顺序标记是代码点 U+FEFF,即零宽度不间断空格。在 utf16
编码的文件中,标准规定,如果它存在于文件开头,则应将其解释为字节顺序标记,而不是 U+FEFF 代码点。
虽然写入会导致在不同的字节序系统上写入不同的文件,但在 2018.10 发布时,在写入文件时将写入字节顺序标记,并且使用 utf16 编码创建的文件将能够在大小端字节序系统上读取。
使用 utf16be 或 utf16le 编码时不使用字节顺序标记。所使用的字节序不受主机 CPU 类型的影响,对于 utf16be 而言为大端序,对于 utf16le 而言为小端序。
为了符合标准,文件开头处的 0xFEFF 字节被解释为零宽度不换行空格,而不是字节顺序标记。对于使用 utf16be 或 utf16le 编码的文件,不会写入字节顺序标记。
从 MoarVM 上的 Rakudo 2018.09 开始,支持 utf16、utf16le 和 utf16be。在 2018.10 中,使用 utf16 写入文件会正确添加字节顺序标记 (BOM)。
示例§
with 'foo'.IO
例程行§
sub lines( = , |c)multi method lines( IO::Handle: , : )multi method lines( IO::Handle: : )
子形式默认采用 $*ARGFILES
,它会将 lines
方法应用于作为第一个参数的对象,并将其余参数传递给它。
该方法将返回一个 Seq
,其每个元素都是句柄中的一行(即由 .nl-in
划分的块)。如果句柄的 .chomp
属性设置为 True
,则 .nl-in
指定的字符将从每一行中剥离。
读取最多 $limit
行,其中 $limit
可以是 Int
、Inf
或 Whatever
(解释为 Inf
)的非负数。如果 :$close
设置为 True
,则会在文件结束或达到 $limit
时关闭句柄。如果未提供句柄,则子例程形式默认为 $*ARGFILES
。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
注意:行是惰性读取的,因此请确保返回的 Seq
已 完全具体化,或者在关闭句柄或尝试使用任何其他更改文件位置的方法时不再需要它。
say "The file contains ",'50GB-file'.IO.open.lines.grep(*.contains: 'Raku').elems," lines that mention Raku";# OUTPUT: «The file contains 72 lines that mention Raku»
您可以在 /proc/*
文件(来自 6.d 版本)中使用 lines
say lines( "/proc/$*PID/statm".IO ); # OUTPUT: «(58455 31863 8304 2 0 29705 0)»
方法 lock§
method lock(IO::Handle:Bool : = False, Bool : = False--> True)
如果文件句柄已打开,则对文件放置一个建议锁定。如果 :$non-blocking
为 True
,则如果无法获取锁定,将使用 X::IO::Lock
fail
;否则,将阻塞直到可以放置锁定。如果 :$shared
为 True
,则将放置共享(读取)锁定;否则,将放置独占(写入)锁定。成功时,返回 True
;如果无法放置锁定(例如,尝试对以写入模式打开的文件句柄放置共享锁定,或尝试对以读取模式打开的文件句柄放置独占锁定),则使用 X::IO::Lock
fail。
您可以再次使用 .lock
用另一个锁定替换现有锁定。要删除锁定,请 close
文件句柄或使用 unlock
。
# One program writes, the other reads, and thanks to locks either# will wait for the other to finish before proceeding to read/write# Writergiven "foo".IO.open(:w)# Readergiven "foo".IO.open
方法 unlock§
method unlock(IO::Handle: --> True)
从文件句柄中移除一个 lock
。如果无法移除,它将返回 True
或引发异常。
例程 words§
multi words(IO::Handle = , = Inf, : --> Seq)multi method words(IO::Handle: = Inf, : --> Seq)
类似于 Str.words
,将句柄的流按连续的空白块(如 Unicode 所定义)分隔,并返回一个由所得“单词”组成的 Seq
。接受一个可选的 $limit
参数,它可以是非负 Int
、Inf
或 Whatever
(解释为 Inf
),以指示仅返回最多 $limit
个单词。如果 Bool
:$close
命名参数设置为 True
,则在返回的 Seq
耗尽时自动关闭句柄。如果没有提供句柄,则子例程形式默认为 $*ARGFILES
。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my := bag .words;say "Most common words: ", .sort(-*.value).head: 5;
注意:在调用 .words
时,实现可能会读取比必要更多的 data。也就是说,$handle.words(2)
可能读取多于两个“单词”的数据,并且对读取方法的后续调用可能无法从获取的两个单词之后的正确位置读取。在调用 .words
之后,文件位置应视为未定义。
方法 split§
method split(IO::Handle: :, |c)
Slurp 句柄的内容,并对其调用 Str.split
,转发任何给定的参数。如果 :$close
命名参数设置为 True
,则在 slurp 之后将 关闭 调用者。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = 'path/to/file'.IO.open;.split: '♥', :close; # Returns file content split on ♥
方法 spurt§
multi method spurt(IO::Handle: Blob , : = False)multi method spurt(IO::Handle: Cool , : = False)
将所有 $data
写入文件句柄,并在完成后关闭它(如果 $close
为 True
)。对于 Cool
$data
,将使用句柄设置为使用的编码(IO::Handle.open
或 IO::Handle.encoding
)。
当句柄处于二进制模式时,喷射 Cool
或当句柄不在二进制模式时喷射 Blob
的行为是未定义的。
方法 print§
multi method print(** --> True)multi method print(Junction --> True)
将给定的 @text
写入句柄,通过调用 .Str
方法将任何非 Str
对象强制转换为 Str
。 Junction
参数 自动线程化,并且不保证打印字符串的顺序。请参阅 write 以写入字节。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = 'path/to/file'.IO.open: :w;.print: 'some text';.close;
方法 print-nl§
method print-nl(IO::Handle: --> True)
将 $.nl-out
属性的值写入句柄。默认情况下,此属性为 
,但请参阅 换行符页面 以了解它在不同平台和环境中遵循的规则。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = 'path/to/file'.IO.open: :w, :nl-out("\r\n");.print: "some text";.print-nl; # prints \r\n.close;
方法 printf§
multi method printf(IO::Handle: Cool , *)
根据给定的格式和参数格式化一个字符串,并将结果.print
到文件句柄中。有关可接受的格式指令的详细信息,请参见sprintf。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = open 'path/to/file', :w;.printf: "The value is %d\n", 32;.close;
方法 out-buffer§
method out-buffer(--> Int) is rw
控制输出缓冲,可以通过open的参数进行设置。将一个int
作为要使用的缓冲区大小(0是可以接受的)。可以采用一个Bool
:True
表示使用默认的、实现定义的缓冲区大小;False
表示禁用缓冲(相当于使用0
作为缓冲区大小)。
最后,可以采用一个Nil
来启用基于 TTY 的缓冲控制:如果句柄是一个 TTY,则禁用缓冲,否则,使用默认的、实现定义的缓冲区大小。
请参见flush以写入当前缓冲区中的数据。更改缓冲区大小会刷新文件句柄。
given 'foo'.IO.open: :w, :1000out-buffer
方法 put§
multi method put(** --> True)multi method put(Junction --> True)
将给定的@text
写入句柄,通过调用.Str
方法将任何非Str
对象强制转换为Str
,并在末尾追加.nl-out
的值。 Junction
参数自动线程化,并且打印的字符串的顺序不能得到保证。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = 'path/to/file'.IO.open: :w;.put: 'some text';.close;
方法 say§
multi method say(IO::Handle: ** --> True)
此方法与put相同,只是它通过调用.gist
而不是.Str
来对其参数进行字符串化。
尝试在句柄 处于二进制模式 时调用此方法将导致引发 X::IO::BinaryMode
异常。
my = open 'path/to/file', :w;.say(Complex.new(3, 4)); # OUTPUT: «3+4i».close;
方法 read§
method read(IO::Handle: Int(Cool) = 65536 --> Buf)
二进制读取;从文件句柄中读取并返回最多$bytes
字节。$bytes
默认为一个特定于实现的值(在 Rakudo 中,$*DEFAULT-READ-ELEMS
的值,默认设置为65536
)。即使句柄不是二进制模式,也可以调用此方法。
(my = 'foo'.IO).spurt: 'I ♥ Raku';given .open
方法 readchars§
method readchars(IO::Handle: Int(Cool) = 65536 --> Str)
读取字符;从文件句柄中读取并返回最多$chars
个字符(字形)。$chars
默认为一个特定于实现的值(在 Rakudo 中,$*DEFAULT-READ-ELEMS
的值,默认设置为65536
)。当句柄处于二进制模式时尝试调用此方法将导致抛出X::IO::BinaryMode
异常。
(my = 'foo'.IO).spurt: 'I ♥ Raku';given .open
方法 write§
method write(IO::Handle: Blob --> True)
将$buf
写入文件句柄。即使句柄不是二进制模式,也可以调用此方法。
方法 seek§
method seek(IO::Handle: Int , SeekType --> True)
将文件指针(即任何后续读取或写入操作将开始的位置)移动到由$offset
指定的字节位置,相对于由$whence
指定的位置,$whence
可以是以下之一
SeekFromBeginning
:文件的开头。SeekFromCurrent
:文件中的当前位置。SeekFromEnd
:文件的末尾。请注意,如果你想定位到文件末尾之前的位置,你需要指定一个负偏移量。
方法 tell§
method tell(IO::Handle: --> Int)
以字节为单位返回文件指针的当前位置。
方法 slurp-rest§
multi method slurp-rest(IO::Handle: :! --> Buf)multi method slurp-rest(IO::Handle: : --> Str)
弃用通知:此方法在 6.d
版本中已弃用。不要在新建代码中使用它,而应使用 .slurp
方法。
从当前文件位置(可能已由之前的读取或 seek
设置)返回文件的剩余内容。如果提供了副词 :bin
,将返回一个 Buf
;否则,返回将是一个具有可选编码 :enc
的 Str
。
方法 slurp§
method slurp(IO::Handle: :, :)
返回从当前文件指针到末尾的所有内容。如果调用者处于二进制模式或如果 $bin
设置为 True
,将返回一个 Buf
,否则将使用调用者的当前 .encoding
对内容进行解码并返回一个 Str
。
如果 :$close
设置为 True
,将在完成读取时关闭句柄。
注意:在 Rakudo 上,此方法在 2017.04 版本中引入;$bin
参数在 2017.10 中添加。
方法 Supply§
multi method Supply(IO::Handle: : = 65536)
返回一个 Supply
,它将以块的形式发出句柄的内容。如果句柄处于二进制模式,则这些块将是 Buf
;如果不是,则使用与 IO::Handle.encoding
相同的编码解码的 Str
。
块的大小由可选的 :size
命名参数和二进制模式下的 65536
字节或非二进制模式下的 65536
个字符决定。
"foo".IO.open(:bin).Supply(:size<10>).tap: *.raku.say;# OUTPUT:# Buf[uint8].new(73,32,226,153,165,32,80,101,114,108)# Buf[uint8].new(32,54,33,10)"foo".IO.open.Supply(:size<10>).tap: *.raku.say;# OUTPUT:# "I ♥ Perl"# " 6!\n"
方法 path§
method path(IO::Handle:)
对于在文件上打开的句柄,这将返回表示该文件的 IO::Path
。对于标准 I/O 句柄 $*IN
、$*OUT
和 $*ERR
,它将返回一个 IO::Special
对象。
方法 IO§
method IO(IO::Handle:)
.path
的别名
方法 Str§
say "foo".IO.open.Str; # OUTPUT: «foo»
例程 close§
method close(IO::Handle: --> Bool)multi close(IO::Handle )
关闭一个打开的文件句柄,成功时返回 True
。如果文件句柄已经关闭,则不会引发错误,但如果你关闭了其中一个标准文件句柄(默认情况下:$*IN
、$*OUT
或 $*ERR
:任何具有 native-descriptor 2
或更低的文件句柄),你将无法重新打开它们。
given "foo/bar".IO.open(:w)
使用 LEAVE
phaser 来关闭句柄是一种常见的惯用法,它确保无论如何离开块,句柄都会关闭。
dosub do-stuff-with-the-file (IO )
注意:与其他一些语言不同,Raku 不使用引用计数,因此 文件句柄在超出作用域时不会关闭。虽然它们会在垃圾回收时关闭,但不能保证垃圾回收会运行。这意味着你必须对用于写入的文件句柄使用显式的 close
,以避免数据丢失,并且对用于读取的文件句柄也建议使用显式的 close
,以便你的程序不会同时打开太多文件,从而在进一步的 open
调用中触发异常。
请注意,一些方法允许提供 :close
参数,以便在方法调用的操作完成后关闭句柄。作为一个更简单的替代方案,IO::Path
类型提供了许多读写方法,让你可以在不直接处理文件句柄的情况下使用文件。
方法 flush§
method flush(IO::Handle: --> True)
将刷新句柄,写入任何缓冲数据。成功时返回 True
;否则,使用 X::IO::Flush
失败。
given "foo".IO.open: :w
方法 native-descriptor§
method native-descriptor(IO::Handle:)
这返回一个操作系统将理解为“文件描述符”的值,并且适合传递给需要文件描述符作为参数的本机函数,例如 fcntl
或 ioctl
。
方法 nl-in§
method nl-in(--> Str) is rw
可以通过 .new
或 open 设置的属性之一。默认为 ["\x0A", "\r\n"]
。获取一个 Str
或 Array
的 Str
,指定此句柄的输入行尾。如果 .chomp
属性设置为 True
,则将在执行 chomp
的例程(例如 get
和 lines
)中去掉这些结尾。
with 'test'.IO
方法 nl-out§
has Str is rw = "\n";
可以通过 .new
或 open 设置的属性之一。默认为 "\n"
。获取一个 Str
,指定此句柄的输出行尾,供方法 .put
和 .say
使用。
with 'test'.IO
方法 opened§
method opened(IO::Handle: --> Bool)
如果句柄已打开,则返回 True
,否则返回 False
。
方法 t §
method t(IO::Handle: --> Bool)
如果句柄打开到 TTY,则返回 True
,否则返回 False
。
创建自定义句柄§
从 6.d 语言(在 Rakudo 编译器版本 2018.08 中提供早期实现)开始,提供了一些帮助方法来简化自定义 IO::Handle
对象的创建。在子类中,只需实现这些方法即可影响所有相关功能。如果句柄要使用文本读/写方法,并且不使用标准 .open
方法,请务必在自定义句柄中调用 .encoding
方法以正确设置解码器/编码器
is IO::Handlemy := IO::URL.new: :URL<raku.org>;# .slurp and print all the content from the website. We can use all other# read methods, such as .lines, or .get, or .readchars. All of them work# correctly, even though we only defined .READ and .EOF.slurp.say;
方法 WRITE§
method WRITE(IO::Handle: Blob \data --> Bool)
每当对句柄执行写操作时都会调用。即使调用了文本写方法,也始终将数据作为 Blob
接收。
is IO::Handlemy = IO::Store.new();my = ::OUT;::OUT = ;.say for <one two three>;::OUT = ;say .lines(); # OUTPUT: «[one two three]»
在此示例中,我们创建一个简单的 WRITE
重定向,它将写入文件句柄的任何内容存储到一个数组中。我们需要先保存标准输出,我们在 $output
中执行此操作,然后通过定义的 IO::Store
/type/IO::Store 类存储所有 print
或 say
的内容。此类中应考虑两件事。默认情况下,IO::Handle
处于二进制模式,因此如果要使用文本,我们需要 TWEAK
对象。其次,如果成功,WRITE
操作应返回 True
。如果失败,它将失败。
方法 READ§
method READ(IO::Handle: Int \bytes --> Buf)
每当对句柄执行读取操作时都会调用。接收请求读取的字节数。返回一个 Buf
,其中包含可用于填充解码器缓冲区或直接从读取方法返回的字节。结果允许少于请求的字节数,包括没有字节。
如果你提供自己的 .READ
,则很可能还需要提供自己的 .EOF
,以便所有功能都能正确运行。
编译器可以在读取操作期间多次调用 .EOF
方法,以确定是否应调用 .READ
。可以从 .READ
请求满足读取操作所需的更多字节,在这种情况下,IO::Handle
或其使用的解码器可能会缓冲额外数据,以满足任何后续读取操作,而无需进行另一个 .READ
调用。
is IO::Handlemy := IO::Store.new();.print( ) for <one two three>;say .read(3).decode; # OUTPUT: «one»say .read(3).decode; # OUTPUT: «two»
在这种情况下,我们已经编程了两个 READ
和 EOF
方法,以及 WRITE
,它将每行存储在一个数组中的一个元素中。read
方法实际上调用 READ
,返回 3 个字节,对应于前两个元素中的三个字符。请注意,IO::Handle
基类负责光标,因为 READ
只是提供对对象整个内容的句柄;基类一次将 READ
1024 * 1024 个字节。如果你的对象计划保存比这更大的字节数,则必须自己处理内部光标。这就是为什么在这个示例中我们实际上不使用 bytes
参数的原因。
方法 EOF§
method EOF(IO::Handle: --> Bool)
指示是否已到达句柄的数据源的“文件结尾”;即无法通过调用 .READ
方法获取更多数据。请注意,这不同于 eof 方法,后者仅在 .EOF
返回 True
以及句柄使用的所有解码器缓冲区(如果有)也为空时才返回 True
。有关示例实现,请参见 .READ
。