используя perl tie :: file с utf-кодированным файлом - PullRequest
3 голосов
/ 15 октября 2011

Можно ли использовать 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");

Ответы [ 3 ]

5 голосов
/ 15 октября 2011

Это недокументировано в Tie::File perldoc , но вы хотите передать параметр discipline => ':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 излишне для этой работы.

(Мой предыдущий ответ об открытии дескриптора файла с правильной кодировкой и передаче глобуса в качестве третьего аргумента для Tie::File не будетработать, так как (1) он не открыл файл в режиме чтения / записи и (2), даже если он это сделал, Tie::File не может или не применяет кодировку для чтения и записи в файлручка)

4 голосов
/ 15 октября 2011
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 - это обходные пути для ошибок, существовавших тогда.)

4 голосов
/ 15 октября 2011

Строка:

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

Пытается привязать @lines к файлу с именем каждой строки test.txt.Поскольку это не файл с именами файлов, я подозреваю, что это tie не удалось.

То, что вы, вероятно, после того, как использовать Tie::File на test.txt.Если вы хотите проверить только первую строку этого файла, вам не нужен цикл.

Так что вам нужно что-то вроде:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...