从文件中读取n个字节的文本

3

我有一个文本文件,我读取第一行以了解它占用了多少字节,

open($fh, "<:raw", $file);
my $len;
while (my $row = <$fh>) {
  $len = length $row;
  last;
};

现在我想从文件的中间行开始读取+100个字节,我该怎么做?

类似这样:

read ($fh, 100, $len/2)

无法确切地理解正确的语法。


你所说的“_从中间行开始_”是指从第一行的中间开始吗? - zdim
1
可能是Perl seek函数的重复问题。 - Ken Y-N
是的,我想把第一行按字节减半。 - DisplayMyName
好的,那么在第一行的一半之后是100个字节...然后呢? - zdim
抱歉没有表达清楚,我想要“读取”,也就是从文件中获取从第x个字节到第y个字节的字符串。 - DisplayMyName
显示剩余2条评论
1个回答

6

在获取线路长度之后

my $row_len = length <$fh>;  # with newline, or (read then) chomp first

使用seek函数将句柄定位到所需位置。

use Fcntl qw(:seek);

seek $fh, $row_len/2, SEEK_SET;

在it技术中,Fcntl提供了常量SEEK_SETSEEK_CURSEEK_END,用于确定第二个参数的位置,可以从文件的开头、当前位置或文件的末尾(通常使用负位置)取得。而0、1、2也可以代替这些常量。

接下来,使用read函数将$bytes读入到$data中。

my $bytes = 100;
my $data;

my $rb = read $fh, $data, $bytes;

其中$rb表示实际从$bytes中读取的字节数。


对于某些文件句柄(例如套接字),read可能无法一次获取所请求的所有数据,因此需要继续读取。例如,可以使用OFFSET(参见文档)来指定要写入字符串的位置。

use bytes qw();

my ($data, $requested, $total_read) = ('', 100, 0); 

while ($total_read < $requested) {
    my $bytes_data = bytes::length $data;
    $total_read += read $fh, $data, $requested - $bytes_data, $bytes_data;
}

现在,read将在$bytes_data位置向$data中写入。如果没有这个偏移量,每次读取都会覆盖$data,可以将所有数据附加到字符串中(或以其他方式累积)。

虽然bytes::length很好,但通常强烈不建议使用bytes pragma


感谢ikegami的评论。

请注意,read不会以任何特殊方式处理“换行符”,而读取可能会从文件的下一行(或多行)开始,而这些换行符字节确实计算,因此会影响您在文件中的位置。

未指定要执行的下一步操作,但可以保持(重新定位和)读取。

请参见此帖子,了解使用seekread在文件中移动的清晰解释。


此外,请记住对于某些句柄(例如套接字),read 可能不会读取请求的那么多字节。需要使用循环。 - ikegami
请注意,最好为seek的最后一个参数(WHENCE)使用命名常量。因此,请使用use Fcntl ':seek'seek $fh, $row_len/2, SEEK_SET - Borodin
1
@Borodin 对的...我考虑过这个问题,认为这可能会使答案范围太广。我会稍微补充一下,谢谢。 - zdim
1
@felwithe,感谢您说明了您的反对理由,非常感谢。(1) 这确实在文档中有提到——您看了吗?就在seek的第一段中,清晰明了,并且附有链接到模块的常量(以及:seek标签)(2) 模块Fcntl加载了C语言的Fcntl.h定义,这是一个用于处理文件描述符的标准实用程序(3) 这样,seek可以使用fseek(3)系统调用的命名常量(4) 这被广泛认为是良好的实践。 - zdim
1
@felwithe 供以后参考:fcntl == 文件控制。我建议阅读Fcntl文档,以欣赏该模块的实用性,并且对于fcntl一般情况,只需在谷歌中输入并向下阅读即可。 - zdim
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接