在Perl中从offset到end读取文本文件的内容

时间:2011-12-22 08:58:20

标签: perl file-io

我正在通过阅读Jeffrey Friedl的优秀Mastering Regular Expressions来教自己Perl和Regex。

在尝试解决从第53页开始的“小邮件实用程序”练习时,我偶然发现了一个问题,即不知道如何将文件内容保存到从偏移开始的变量中。< / p>

所以这是我的(缩短的)剧本。

my ($body, $line, $subject); 
$body = $line = $subject = "";

open(MYFILE, "king.in") || die("Could not open file!");    
# Read the file's content line by line
while ($line = <MYFILE>)
{   
    # An empty line marks the beginning of the body
    if ($line =~ m/^\s+$/ ) {
        # HERE IS THE ISSUE
        # Save the file content starting from the current line
        # to the end of the file into $body
        last; 
    }

    if ($line =~ m/^subject: (.*)/i) {
        $subject = $1;
    }
    # Parse additional data from the mail header
}
close(MYFILE);

print "Subject: Re: $subject\n";
print "\n" ;
print $body;

我做了一些在线研究,但无法弄清楚如何将文件的其余部分(即电子邮件正文)放入变量$ body中。

我发现我可以使用$pos = tell(MYFILE);

以字节为单位获取文件中的当前位置

最终,我最终将文件的行首先放入数组中,但不满意solution

如何将文件内容从偏移量(作为行号或字节)保存到$ body中?

修改 我的解决方案 - 由vstm提供 - 是在遇到标记正文开头的空行时使用$body = join("", <MYFILE>)读取文件的其余部分。 我写的整个脚本可以找到here

虽然这对我来说很有用,但我仍然想知道如何在Perl中说(优雅地)“给我这个文件的x到z行。”

感谢大家的建议。

3 个答案:

答案 0 :(得分:2)

变量$.将为您提供当前文件句柄的行号。文档here.

如果要在文件中获取字节偏移量,可以使用seek设置文件句柄位置。但通常情况下,你真的不想这样做,除非字节实际上是你想要的偏移量。

最简单的解决方案可能是使用输入记录分隔符。将其设置为undef将会污染文件,而不是逐行读取:

my $text;
my $subject;
while (<MYFILE>) {
    if (/^subject: /i) {  # /i flag to ignore case
        $subject = $_;
    } elsif (/^\s*$/) {
        local $/;  
        $text = <MYFILE>;
    }
}

这也将结束循环,因为它已达到eof。

答案 1 :(得分:1)

不要立即停止,你可以设置一个标志,上面写着“现在我正在读取身体”。像那样:

my $inbody = 0;

while ($line = <MYFILE>)
{   
    if($inbody) {
        $body .= $line;
        next;
    }
    # An empty line marks the beginning of the body
    if ($line =~ m/^\s+$/ ) {
        # HERE IS THE ISSUE
        # Save the file content starting from the current line
        # to the end of the file into $body
        $inbody = 1;
        next;
    }

    if ($line =~ m/^subject: (.*)/i) {
        $subject = $1;
    }
    # Parse additional data from the mail header
}

这就像一台迷你状态机。首先它在“标题” - 状态中,如果读取第一个空换行符,它将切换到“body”状态,并将正文附加到变量。

或者,您可以将MYFILE - 句柄的其余部分放入原始while循环末尾和close之前的正文:

# This would be your original while loop, (I've just shortened it)
while ($line = <MYFILE>)
{   
    if ($line =~ m/^\s+$/ ) {
        last;
    }
    # Parse additional data from the mail header
}

# The MYFILE-handle is now still valid and at the beginning of the body
$body = join("", <MYFILE>);

# now you can close the handle
close(MYFILE);

答案 2 :(得分:0)

您可以更改输入记录分隔符:

local $/;
$body = <MYFILE>;