簡體   English   中英

使用perl tie :: file和utf編碼文件

[英]using perl tie::file with utf encoded file

我可以將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");

這在Tie::File perldoc中未被記錄,但是當你綁定文件時,你想要通過discipline => ':encoding(UTF-16LE)'選項:

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

請注意,第三個參數是與綁定數組關聯的文件的名稱。 Tie::File將自動打開並管理文件句柄; 沒有必要自己open文件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作為第三個arg傳遞給Tie::File將不起作用,因為(1)它沒有以讀/寫模式打開文件和(2)即使它確實如此, Tie::File也不能或不會對讀取和寫入文件句柄應用編碼)

這條線:

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
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是當時存在的bug的解決方法。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM