【问题标题】:using perl tie::file with utf encoded file使用带有 utf 编码文件的 perl tie::file
【发布时间】:2011-10-19 05:00:39
【问题描述】:

我可以将Tie::File 与utf 编码的输出文件一起使用吗?我无法让它正常工作。 我要做的是打开这个 utf 编码文件,从文件中删除匹配字符串并重命名文件。

代码:

use strict;
use warnings;
use Tie::File;
use File::Copy;

my ($input_file) = qw (test.txt);

open my $infh, "<:encoding(UTF-16LE)", $input_file or die "cannot open '$input_file': $!";

for (<$infh>) {
    tie my @lines, "Tie::File", $_;
    shift @lines if $lines[0] =~ m/MyHeader/;
    untie @lines;
    my ($name) = /^(.*).csv/i;
    move($_, $name . ".dat");
}

close $infh
    or die "Cannot close '$input_file': $!";

代码:(更新)

my ($input_file) = qw (test.txt);
my $qfn_in = $input_file;
my $qfn_out = $qfn_in . ".dat";

open(my $fh_in, "<:raw:perlio:encoding(UTF-16le):crlf:utf8", $qfn_in)
   or die("Can't open \"$qfn_in\": $!\n");

open(my $fh_out, ">:raw:perlio:encoding(UTF-16le):crlf:utf8", $qfn_out)
   or die("Can't open \"$qfn_out\": $!\n");

while (<$fh_in>) {
   next if $. == 1 && /MyHeader/; 
   print($fh_out $_)
      or die("Can't write to \"$qfn_out\": $!");
}

close($fh_in);
close($fh_out) or die("Can't write to \"$qfn_out\": $!");

rename($qfn_out, $qfn_in)
   or die("Can't rename: $!\n");

【问题讨论】:

    标签: perl


    【解决方案1】:

    这在Tie::File perldoc 中没有记录,但您想在绑定文件时传递discipline =&gt; ':encoding(UTF-16LE)' 选项:

    tie my @lines, 'Tie::File', $input_file, discipline => ':encoding(UTF-16LE)'
    

    请注意,第三个参数是与绑定数组关联的文件的名称。 Tie::File会自动为你打开和管理文件句柄;无需自己在文件上调用open

    @lines 现在包含文件的内容,所以接下来要做的是检查第一行:

    if ($lines[0] =~ m/pattern/) {
        my $line = shift @lines;
        untie @lines;   # rewrites, closes the file, w/o first line
        my ($name) = $line =~ /^(.*).csv/i;
        rename $input_file, "$name.dat";
    }
    

    但我同意 TLP 的观点,即 Tie::File 对于这份工作来说太过分了。

    (我之前关于使用正确编码打开文件句柄并将 glob 作为第三个参数传递给 Tie::File 的回答不起作用,因为(1)它没有以读/写模式打开文件并且( 2) 即使这样做了,Tie::File 也不能或不对文件句柄的读取和写入应用编码)

    【讨论】:

    • 谢谢,我也试过了,但收到了这些消息:Filehandle $infh opened only for input at /lib/perl5/5.8/Tie/File.pm line 907, &lt;$infh&gt; line 250. Couldn't write record: Bad file descriptor at /lib/perl5/5.8/Tie/File.pm line 907, &lt;$infh&gt; line 250.
    • 即使我更新的答案也很狡猾。当Tie::File 重写文件时,我不知道你是否可以相信它会在正确的地方寻找和截断。恕我直言,尝试使用 Tie::File 只会让这个问题变得更加困难。
    【解决方案2】:
    my $qfn_in = ...;
    my $qfn_out = $qfn_in . ".tmp";
    
    open(my $fh_in, "<:raw:perlio:encoding(UTF-16le):crlf:utf8", $qfn_in)
       or die("Can't open \"$qfn_in\": $!\n");
    
    open(my $fh_out, ">:raw:perlio:encoding(UTF-16le):crlf:utf8", $qfn_out)
       or die("Can't open \"$qfn_out\": $!\n");
    
    while (<$fh_in>) {
       next if $. == 1 && /MyHeader/;
       print($fh_out $_)
          or die("Can't write to \"$qfn_out\": $!");
    }
    
    close($fh_in);
    close($fh_out) or die("Can't write to \"$qfn_out\": $!");
    
    rename($qfn_out, $qfn_in)
       or die("Can't rename: $!\n");
    

    :perlio:utf8 是针对当时存在的错误的解决方法。)

    【讨论】:

    • 您需要(或不需要)哪些 Perl 版本的变通方法?我不会想到去做。这很烦人,你必须先弹出 crlf 然后再放回去。几周前我几乎把这一切都解决了,但似乎找不到我的笔记。我希望:raw 被简单地称为:uncrlf
    • @tchrist,我看到有人说需要 utf8
    • @tchrist,要明确“删除:perlio”实际上意味着“禁用缓冲”。我不知道get_layers返回的图层有什么可见效果。
    • @ikegami - 一切正常,除了重命名。它仍然保持相同的文件名,我也没有看到.tmp 文件。我做了my $qfn_in = $input_file(见我的原始代码)。它删除了正确的匹配行,我只需要将文件从test.txt 重命名为test.dat。谢谢
    • @jdamae,Tie::File 编辑就位,所以我也这样做了。如果您不想就地编辑,请将$qfn_out 设置为输出文件并删除rename
    【解决方案3】:

    行:

    tie my @lines, "Tie::File", $_;
    

    尝试将@lines 绑定到每行名称为test.txt 的文件。由于它似乎不是包含文件名的文件,我怀疑 tie 失败。

    您可能想要在test.txt 上使用Tie::File。如果您只想检查该文件的第一行,则不需要循环。

    所以你需要这样的东西:

    use autodie;  #handy to check for fatal errors
    tie my @lines, "Tie::File", $input_file;
    shift @lines if $lines[0] =~ /MyHeader/;
    untie @lines;
    if ($input_file =~ /(.+).csv/i) {
        move($input_file, $1);
    }
    

    但是有更简单的方法可以检查文件的第一行。这将检查一个文件:

    perl -we '$_=<>; print if /MyHeader/; print <>;' test.txt > test.dat
    

    【讨论】:

    • 所以,你的意思是tie my @lines, "Tie::File", $input_file;'? 我也尝试删除循环。现在,我收到了其他消息:Use of uninitialized value in pattern match (m//), Use of uninitialized value in concatenation (.), Use of uninitialized value in -s,rename, string, stat at perl5/5.8/File/Copy.pm
    • 也感谢您的意见。虽然,我必须用编码检查打开这个文件。该特定检查在字符串之前还有一些其他字符。所以,我还在用文件句柄找出消息(参见对 mob 的回复)
    猜你喜欢
    • 1970-01-01
    • 2012-10-23
    • 2011-03-11
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2017-04-23
    • 2022-07-20
    • 1970-01-01
    相关资源
    最近更新 更多