我正在寻找一种逐行读取文件句柄的方法(然后在每一行上执行一个函数),具有以下转折:我想要视为"行"的东西应该通过改变字符来终止,而不仅仅是我定义为的单个字符$/.我现在$INPUT_RECORD_SEPARATOR或$/不支持正则表达式或传递一个字符列表作为行终止符,这就是我的问题所在.
我的文件句柄来自进程的stdout.因此,我无法在文件句柄内寻找并且完整内容不能立即获得,而是在执行过程时逐位产生.我希望能够使用我handler在示例中调用的函数将时间戳附加到进程生成的每个"行" .每一行都应该在程序生成后立即处理.
不幸的是,我只能提出一种方法,既可以handler立即执行函数,但看起来非常低效,或者使用缓冲区的方式,但只会导致handler函数的"分组"调用,从而产生错误的时间戳.
事实上,在我的具体情况下,我的正则表达式甚至会非常简单并且只是阅读/\n|\r/.因此,对于这个特殊问题,我甚至不需要完整的正则表达式支持,而只需要将多个字符视为行终止符.但$/不支持这一点.
有没有一种有效的方法来解决Perl中的这个问题?
下面是一些快速的伪perl代码来演示我的两种方法:
这看起来像这样:
my $acc = "";
while (read($fd, my $b, 1)) {
$acc .= $b;
if ($acc =~ /someregex$/) {
handler($acc);
$acc = "";
}
}
Run Code Online (Sandbox Code Playgroud)
这里的优点是,handler一旦读取了足够的字节,就会立即调度.缺点是,我们执行字符串追加并检查我们读取的每个字节的正则表达式$fd.
这看起来像这样:
my $acc = "";
while (read($fd, my $b, $bufsize)) {
if ($b =~ /someregex/) {
my @parts = split /someregex/, $b;
# for brevity lets assume we always get more than 2 parts...
my $first = shift @parts;
handler(acc . $first);
my $last = pop @parts;
foreach my $part (@parts) {
handler($part);
}
$acc = $last;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的优点是,我们更高效,因为我们只检查每个$bufsize字节.缺点是执行handler必须等到$bufsize读取字节.
将 $INPUT_RECORD_SEPARATOR 设置为正则表达式不会有帮助,因为 Perlreadline也使用缓冲 IO。诀窍是使用第二种方法,但使用 unbufferedsysread而不是read. 如果您sysread来自管道,则一旦数据可用,调用就会返回,即使整个缓冲区无法被填充(至少在 Unix 上)。