class IO::CatHandle is IO::Handle { }

此类自 2017.06 版起在 Rakudo 中提供。

IO::CatHandle 类提供了一种创建 IO::Handle 的方法,该方法无缝地从多个 IO::HandleIO::Pipe 源收集输入。

所有 IO::Handle 的方法都已实现,虽然尝试使用写入方法(目前)会引发异常;但可以在任何可以使用只读 IO::Handle 的地方使用 IO::CatHandle

方法§

method new§

method new(*@handles:&on-switch:$chomp = True,
           :$nl-in = ["\n""\r\n"], Str :$encodingBool :$bin)

创建一个新的 IO::CatHandle 对象。

@handles 位置参数指示 IO::CatHandle 读取的句柄源,并且可以处理 CoolIO::PathIO::Handle(包括 IO::Pipe)对象的混合集合。由于 IO::CatHandle 的输入正在处理(因此操作不会在 .new 调用期间发生,而仅在需要 @handles 的数据时发生),它将遍历 @handles 列表,按如下方式处理每个参数

  • Cool 对象将强制转换为 IO::Path

  • IO::Path 对象将使用 IO::CatHandle(调用者)的属性打开以供读取,用于 open 调用;

  • 未打开的 IO::Handle 对象将以与 IO::Path 对象相同的方式打开;

  • 并且已经打开的 IO::Handle 对象的所有属性都将设置为调用者 IO::CatHandle 的属性。

简而言之,所有 @handles 最终都作为 IO::Handle 对象结束,这些对象以与调用者 IO::CatHandle 相同的模式和属性打开。

有关 :&on-switch 命名参数的详细信息,请参阅 .on-switch 方法,默认情况下未设置。

命名参数 :$encoding 指定句柄的编码,并接受与 IO::Handle.encoding 相同的值。如果希望句柄处于二进制模式,请将命名参数 :$bin 设置为 True。尝试同时指定已定义的 :$encodingTrue:$bin 是一个致命错误,会导致抛出 X::IO::BinaryAndEncoding 异常。如果既未设置 :$encoding,也未将 :$bin 设置为真值,则句柄将默认为 utf8 编码。

参数 :$chomp:$nl-inIO::Handle 中的含义相同,并采用相同的值作为默认值。

方法 chomp§

method chomp(IO::CatHandle:D:is rw

将调用者的 $.chomp 属性设置为分配的值。所有源句柄(包括活动句柄)都将使用提供的 $.chomp 值。

(my $f1 = 'foo'.IO).spurt: "A\nB\nC\n";
(my $f2 = 'bar'.IO).spurt: "D\nE\n";
with IO::CatHandle.new: $f1$f2 {
    # .chomp is True by default: 
    (.get xx 2).raku.say# OUTPUT: «("A", "B").Seq␤» 
 
    .chomp = False;
    (.get xx 3).raku.say# OUTPUT: «("C\n", "D\n", "E\n").Seq␤» 
    .close
}

方法 nl-in§

method nl-in(IO::CatHandle:D:is rw

将调用者的 $.nl-in 属性设置为分配的值,该值可以是 StrListStr,其中每个 Str 对象都表示行尾字符串。所有源句柄(包括活动句柄)都将使用提供的 $.nl-in 值。请注意,源句柄边界始终被视为一个新的换行符。

(my $f1 = 'foo'.IO).spurt: "A\nB\nC";
(my $f2 = 'bar'.IO).spurt: "DxEx";
with IO::CatHandle.new: $f1$f2 {
    # .nl-in is ["\n", "\r\n"] by default: 
    (.get xx 2).raku.say# OUTPUT: «("A", "B").Seq␤» 
 
    .nl-in = 'x';
    (.get xx 3).raku.say# OUTPUT: «("C", "D", "E").Seq␤» 
    .close
}

方法 close§

method close(IO::CatHandle:D: --> True)

关闭当前活动的源句柄以及任何已打开的源句柄,并清空源句柄队列。与常规 IO::Handle 不同,在 IO::CatHandle 上通常不需要显式调用 .close,因为仅仅耗尽所有输入就会关闭所有需要关闭的句柄。

with IO::CatHandle.new: @bunch-of-handles {
    say .readchars: 42;
    .close# we are done; close all the open handles 
}

方法 comb§

method comb(IO::CatHandle:D: |args --> Seq:D)

读取句柄并处理其内容的方式与 Str.comb 相同,采用相同参数。在调用此方法时,实现可能会完全读取所有源句柄的内容

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
IO::CatHandle.new($f1$f2).comb(2).raku.say;
# OUTPUT: «("fo", "ob", "ar").Seq␤» 

方法 DESTROY§

method DESTROY(IO::CatHandle:D:)

调用 .close。此方法不能直接使用,但会在垃圾回收期间调用。

方法 encoding§

multi method encoding(IO::CatHandle:D:)
multi method encoding(IO::CatHandle:D: $new-encoding)

将调用者的 $.encoding 属性设置为提供的值。有效值与 IO::Handle.encoding 接受的值相同(使用值 Nil 切换到二进制模式)。所有源句柄(包括活动句柄)都将使用提供的 $.encoding 值。

(my $f1 = 'foo'.IO).spurt: 'I ♥ Raku';
(my $f2 = 'bar'.IO).spurt: 'meow';
with IO::CatHandle.new: $f1$f2 {
    # .encoding is 'utf8' by default: 
    .readchars(5).say# OUTPUT: «I ♥ R␤» 
 
    .encoding: Nil# switch to binary mode 
    .slurp.say# OUTPUT: «Buf[uint8]:0x<6B 75 6D 65 6F 77>␤» 
}

方法 eof§

method eof(IO::CatHandle:D: --> Bool:D)

如果读取操作已耗尽源句柄队列(包括最后一个句柄的内容),则返回 True注意:在检查源句柄队列时,调用此方法可能会导致一个或多个 .on-switch 调用,并且 源句柄队列可能会耗尽

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
with IO::CatHandle.new: :on-switch{ print 'SWITCH! ' }$f1$f2 {
                   # OUTPUT: «SWITCH! » 
    .eof.say;      # OUTPUT: «False␤» 
    .readchars(3);
    .eof.say;      # OUTPUT: «SWITCH! False␤» 
 
    .slurp;        # OUTPUT: «SWITCH! » 
    .eof.say;      # OUTPUT: «True␤» 
}

此处应用于 IO::Handle.eof 的不可寻址句柄和空文件的相同注意事项。

方法 get§

method get(IO::CatHandle:D: --> Bool:D)

从句柄返回一行输入,新行字符串由 $.nl-in 属性 的值定义,如果 $.chomp 属性 设置为 True,则该值将从行中移除。当没有更多输入时,返回 Nil。当句柄 处于二进制模式 时,调用此方法会出错,从而导致抛出 X::IO::BinaryMode 异常。

(my $f1 = 'foo'.IO).spurt: "a\nb\nc";
(my $f2 = 'bar'.IO).spurt: "d\ne";
my $cat = IO::CatHandle.new: $f1$f2;
.say while $_ = $cat.get# OUTPUT: «a␤b␤c␤d␤e␤» 

方法 getc§

method getc(IO::CatHandle:D: --> Bool:D)

从句柄返回一个输入字符。在 IO::Handle.getc 中描述的所有注意事项都适用。当没有更多输入时,返回 Nil。当句柄 处于二进制模式 时,调用此方法会出错,从而导致抛出 X::IO::BinaryMode 异常。

(my $f1 = 'foo'.IO).spurt: 'I ♥ Raku';
(my $f2 = 'bar'.IO).spurt: 'meow';
my $cat = IO::CatHandle.new: $f1$f2;
.say while $_ = $cat.getc# OUTPUT: «I␤ ␤♥␤ ␤R␤a␤k␤u␤m␤e␤o␤w␤» 

方法 handles§

定义为

method handles(IO::CatHandle:D: --> Seq:D)

返回一个 Seq,其中包含当前活动的句柄以及通过调用 next-handle 产生的所有剩余源句柄。如果调用者已被完全消耗,则返回一个空的 Seq

在处理 IO::ArgFiles 时,此方法特别方便,因为您希望分别处理每个文件句柄

# print at most the first 2 lines of each file in $*ARGFILES: 
.say for flat $*ARGFILES.handles.map: *.lines: 2

多次调用此方法是可以接受的;.handles.head 是获取当前活动句柄的有效习语。如果在返回的 Seq 的元素的 具体化 之间,句柄通过其他方式进行切换,则 Seq 产生的下一个元素将是调用者的下一个句柄,而不是如果没有发生切换,则会产生的句柄

(my $file1 := 'file1'.IO).spurt: "1a\n1b\n1c";
(my $file2 := 'file2'.IO).spurt: "2a\n2b\n2c";
(my $file3 := 'file3'.IO).spurt: "3a\n3b\n3c";
my $cat := IO::CatHandle.new: $file1$file2$file3;
for $cat.handles {
    say .lines: 2;
    $cat.next-handle;
}
# OUTPUT: «(1a 1b)␤(3a 3b)␤»

同样,具体化返回的 Seq 会消耗调用者的源句柄,并且一旦完全具体化,调用者就会被完全消耗。

方法 IO§

method IO(IO::CatHandle:D:)

.path 的别名

方法 lines§

method lines(IO::CatHandle:D: $limit = Inf:$close --> Seq:D)

IO::Handle.lines 相同。请注意,源句柄之间的边界被认为是换行符。

(my $f1 = 'foo'.IO).spurt: "foo\nbar";
(my $f2 = 'bar'.IO).spurt: 'meow';
IO::CatHandle.new($f1$f2).lines.raku.say;
# OUTPUT: «("foo", "bar", "meow").Seq␤» 

注意:如果 :$closeFalse,则完全消耗的句柄仍然会被关闭。

方法 lock§

method lock(IO::CatHandle:D: Bool:D :$non-blocking = FalseBool:D :$shared = False --> True)

IO::Handle.lock 相同。如果 源句柄队列已用尽,则返回 Nil

仅锁定当前活动的源句柄。 .on-switch Callable 可用于在 CatHandle 处理句柄时方便地锁定/解锁句柄。

方法 native-descriptor§

method native-descriptor(IO::CatHandle:D: --> Int:D)

返回当前活动的源句柄的 native-descriptor,如果 源句柄队列已用尽,则返回 Nil

由于 CatHandle 在完成后会关闭源句柄,因此如果源句柄作为 CoolIO::Path 对象传递给 .new,则连续的源句柄可能具有相同的本机描述符。

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
with IO::CatHandle.new: $f1$f2$*IN {
    repeat { .native-descriptor.say } while .next-handle;
    # OUTPUT: «13␤13␤9␤» 
}

方法 next-handle§

method next-handle(IO::CatHandle:D: --> IO::Handle:D)

将活动源句柄切换到源句柄队列中的下一个句柄,该句柄是 .new@handles 属性中给出的源。

Cool 源“句柄”强制转换为 IO::Path;使用调用者的 $.nl-in$.chomp$.encoding 属性打开 IO::Path 和未打开的 IO::Handle 源句柄以进行读取;已打开的 IO::Handle 对象的相同属性将更改为调用者属性的值。

每当 CatHandle 的方法需要切换到下一个源句柄时,都会自动调用此方法,触发 .on-switch Callable 被调用,并在 .new 调用期间调用一次。即使源句柄队列已用尽,每次调用此方法时,.on-switch 仍将继续触发。请注意,通常达到当前活动源句柄的 EOF 不会触发 .next-handle 调用,而是需要更多数据的进一步读取操作。

(my $f1 = 'foo'.IO).spurt: "a\nb";
(my $f2 = 'bar'.IO).spurt: "c\nd";
with IO::CatHandle.new: :on-switch{ say '▸ Switching' }$f1$f2 {
    say 'one';
    .next-handle.^name.say;
    say 'two';
    .next-handle.^name.say;
    say 'three';
    .next-handle.^name.say;
    # OUTPUT: 
    # ▸ Switching 
    # one 
    # ▸ Switching 
    # IO::Handle 
    # two 
    # ▸ Switching 
    # Nil 
    # three 
    # ▸ Switching 
    # Nil 
}

方法 on-switch§

has &.on-switch is rw

可以在 .new 调用期间设置并稍后通过赋值更改的属性之一。默认情况下未指定。采用 .count012InfCallable。每次 .next-handle 时都会调用,这在 .new 调用期间发生一次,然后每次将源句柄切换到队列中的下一个句柄时,或手动调用 .next-handle 方法时都会发生。

如果 &.on-switch.count0,则它不接收任何参数;如果为 1,则它接收当前活动句柄;如果为 2Inf,则它接收当前活动句柄和最后一个活动句柄作为位置参数(按此顺序)。在第一次 &.on-switch 执行时,“最后一个活动句柄”参数为 Nil。在源句柄队列耗尽时,“当前活动句柄”参数为 Nil,并且之后进行的所有执行都将两个参数作为 Nil

(my $f1 = 'foo'.IO).spurt: "A\nB\nC";
(my $f2 = 'bar'.IO).spurt: "D\nE";
 
my $line;
my $cat = IO::CatHandle.new: :on-switch{ $line = 1 }$f1$f2;
say "{$cat.path}:{$line++} $_" for $cat.lines;
# OUTPUT: 
# foo:1 A 
# foo:2 B 
# foo:3 C 
# bar:1 D 
# bar:2 E 
my @old-stuff;
sub on-switch ($new$old{
    $new and $new.seek: 1SeekFromBeginning;
    $old and @old-stuff.push: $old.open.slurp: :close;
}
 
(my $f1 = 'foo'.IO).spurt: "A\nB\nC";
(my $f2 = 'bar'.IO).spurt: "D\nE";
my $cat = IO::CatHandle.new: :&on-switch$f1$f2;
$cat.lines.raku.say# OUTPUT: «("", "B", "C", "", "E").Seq␤» 
@old-stuff.raku.say# OUTPUT: «["A\nB\nC", "D\nE"]␤» 

方法 open§

method open(IO::CatHandle:D: --> IO::CatHandle:D)

返回调用者。此方法的目的是仅使 CatHandle 可用于使用 IO::Handle 打开内容。您永远不必有意调用此方法。

方法 opened§

method opened(IO::CatHandle:D: --> Bool:D)

如果调用者有任何源句柄,则返回 True,否则返回 False

say IO::CatHandle.new      .opened# OUTPUT: «False␤» 
say IO::CatHandle.new($*IN).opened# OUTPUT: «True␤» 
 
(my $f1 = 'foo'.IO).spurt: "A\nB\nC";
with IO::CatHandle.new: $f1 {
    .opened.say# OUTPUT: «True␤» 
    .slurp;
    .opened.say# OUTPUT: «False␤» 
}

方法 path§

method path(IO::CatHandle:D:)

返回当前活动源句柄的 .path 属性的值,或者如果 IO/CatHandle#method_next-handle 源句柄队列已耗尽,则返回 Nil。基本上,如果您的 CatHandle 基于文件,这是获取 CatHandle 当前正在从中读取的文件路径的方法。

(my $f1 = 'foo'.IO).spurt: "A\nB\nC";
(my $f2 = 'bar'.IO).spurt: "D\nE";
 
my $line;
my $cat = IO::CatHandle.new: :on-switch{ $line = 1 }$f1$f2;
say "{$cat.path}:{$line++} $_" for $cat.lines;
# OUTPUT: 
# foo:1 A 
# foo:2 B 
# foo:3 C 
# bar:1 D 
# bar:2 E 

方法 read§

method read(IO::CatHandle:D: Int(Cool:D$bytes = 65536 --> Buf:D)

从句柄中读取最多 $bytes 字节,并在 Buf 中返回它们。$bytes 默认为实现特定的值(在 Rakudo 中,$*DEFAULT-READ-ELEMS 的值,默认设置为 65536)。允许对非二进制模式的句柄调用此方法。

(my $f1 = 'foo'.IO).spurt: 'meow';
(my $f2 = 'bar'.IO).spurt: Blob.new: 456;
with IO::CatHandle.new: :bin$f1$f2 {
    say .read: 2;    # OUTPUT: «Buf[uint8]:0x<6d 65>␤» 
    say .read: 2000# OUTPUT: «Buf[uint8]:0x<6f 77 04 05 06>␤» 
}
 
# Non-binary mode is OK too: 
with IO::CatHandle.new: $f1$f2 {
    say .get;        # OUTPUT: «meow␤» 
    say .read: 2000# OUTPUT: «Buf[uint8]:0x<04 05 06>␤» 
}

方法 readchars§

method readchars(IO::CatHandle:D: Int(Cool:D$chars = 65536 --> Str:D)

返回从句柄中读取的最多 $chars 个字符的 Str$chars 默认为实现特定的值(在 Rakudo 中,$*DEFAULT-READ-ELEMS 的值,默认设置为 65536)。不允许对以二进制模式打开的句柄调用此方法,这样做会导致抛出 X::IO::BinaryMode 异常。

(my $f1 = 'foo'.IO).spurt: 'Raku loves to';
(my $f2 = 'bar'.IO).spurt: ' meow';
 
with IO::CatHandle.new: $f1$f2 {
    say .readchars: 11;   # OUTPUT: «Raku loves ␤» 
    say .readchars: 1000# OUTPUT: «to meow␤» 
}

方法 seek§

method seek(IO::CatHandle:D: |c)

在当前活动源句柄上调用 .seek,将所有参数转发给它,并返回结果。如果 IO/CatHandle#method_next-handle 源句柄队列已耗尽,则返回 Nil注意:此方法不会执行任何源句柄切换,因此在当前源句柄的末尾之后进行搜索不会搜索队列中的下一个源句柄,并且在当前源句柄的开头之后进行搜索是致命错误。另请参阅 .next-handle,以了解有关何时切换源句柄的详细信息。

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
 
with IO::CatHandle.new: $f1$f2 {
    .get.say;                     # OUTPUT: «foo␤» 
    .seek: -2SeekFromCurrent;
    .readchars(2).say;            # OUTPUT: «oo␤» 
    .seek: 1000SeekFromCurrent# this doesn't switch to second handle! 
    .readchars(3).say;            # OUTPUT: «bar␤» 
    try .seek: -4;                # this won't seek to previous handle! 
    say ~$!;                      # OUTPUT: «Failed to seek in filehandle: 22␤» 
}

方法 tell§

method tell(IO::CatHandle:D: --> Int:D)

在当前活动源句柄上调用 .tell 并返回结果。如果 源句柄队列已耗尽,则返回 Nil

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
 
with IO::CatHandle.new: $f1$f2 {
    .get.say;                   # OUTPUT: «foo␤» 
    .tell.say;                  # OUTPUT: «3␤» 
    .seek: -2SeekFromCurrent;
    .tell.say;                  # OUTPUT: «1␤» 
    say .readchars: 3;          # OUTPUT: «oob␤» 
    .tell.say;                  # OUTPUT: «2␤» 
    }

方法 slurp§

method slurp(IO::CatHandle:D:)

读取所有源句柄的所有可用输入,如果句柄处于 二进制模式,则以 Buf 形式返回,否则以 Str 形式返回。如果 源句柄队列已耗尽,则返回 Nil

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
 
IO::CatHandle.new(      $f1$f2).slurp.say# OUTPUT: «foobar␤» 
IO::CatHandle.new(:bin$f1$f2).slurp.say# OUTPUT: «Buf[uint8]:0x<66 6f 6f 62 61 72>␤» 
IO::CatHandle.new                .slurp.say# OUTPUT: «Nil␤» 

方法 split§

method split(IO::CatHandle:D: |args --> Seq:D)

读取句柄并处理其内容,处理方式与 Str.split 相同,采用相同的参数。实现可能会在调用此方法时完全吸收所有源句柄的内容

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
IO::CatHandle.new($f1$f2).split(/o+/).raku.say;
# OUTPUT: «("f", "bar").Seq␤» 

方法 Str§

method Str(IO::CatHandle:D: --> Str:D)

在当前活动源句柄上调用 .Str 并返回结果。如果 源句柄队列已耗尽,则返回一个实现定义的字符串(在 Rakudo 中为 '<closed IO::CatHandle>')。

方法 Supply§

method Supply(IO::CatHandle:D: :$size = 65536 --> Supply:D)

返回一个 Supply,该 Supply.read(如果句柄处于 二进制模式)或 .readchars(如果句柄不处于二进制模式)提供支持,读取 :$size 字节或字符。:$size 默认为实现特定的值(在 Rakudo 中,为 $*DEFAULT-READ-ELEMS 的值,默认设置为 65536)。

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
react whenever IO::CatHandle.new($f1$f2).Supply: :2size {.say}
# OUTPUT: «fo␤ob␤ar␤» 
 
react whenever IO::CatHandle.new(:bin$f1$f2).Supply: :2size {.say}
# OUTPUT: «Buf[uint8]:0x<66 6f>␤Buf[uint8]:0x<6f 62>␤Buf[uint8]:0x<61 72>␤» 

方法 t§

method t(IO::CatHandle:D: --> Bool:D)

在当前活动源句柄上调用 .t,该方法会告知句柄是否是 TTY,并返回结果。如果 源句柄队列已耗尽,则返回 False

(my $f1 = 'foo'.IO).spurt: 'foo';
with IO::CatHandle.new: $f1$*IN {
    repeat { .t.say } while .next-handle# OUTPUT: «False␤True␤» 
}

方法 unlock§

method unlock(IO::CatHandle:D:)

IO::Handle.unlock 相同。如果 源句柄队列已耗尽,则返回 Nil

仅解锁当前活动的源句柄。可以使用 .on-switch Callable 在 CatHandle 处理句柄时方便地锁定/解锁句柄。

方法 words§

method words(IO::CatHandle:D: $limit = Inf:$close --> Seq:D)

IO::Handle.words 相同(包括有关读取比生成一定数量的单词所需更多数据的警告)。请注意,源句柄之间的边界被视为单词边界。

(my $f1 = 'foo'.IO).spurt: 'foo bar';
(my $f2 = 'bar'.IO).spurt: 'meow';
IO::CatHandle.new($f1$f2).words.raku.say;
# OUTPUT: «("foo", "bar", "meow").Seq␤» 

注意:如果 :$closeFalse,则完全消耗的句柄仍然会被关闭。