1

我试图检测上传的文件是否是有效的 UTF-8,然后才对其内容进行一些操作。它可以检测到非 UTF-8 文件,但如果文件是有效的 UTF-8,则没有要处理的内容。没有要while(){}循环处理的数据。我的错误在哪里?

use utf8;
use CGI qw(:all -utf8);
use Encode;

my $q           = new CGI;

my $file        = $q->param('importfile');
my $file_handle = $q->upload('importfile');
my $fhtest      = do {
        local $/;
        <$file_handle>;
};

my $utf8;
eval { $utf8 = decode( "utf8", $fhtest, Encode::FB_CROAK ) };
if ($@) {
        die 'Not a valid UTF-8 file';
}

binmode $file_handle, ':encoding(UTF-8)';
while (<$file_handle>) {
        chomp();
        # my code here
}
4

2 回答 2

2

当你使用readline(aka <$fh>) 时,你会在你离开的地方阅读下一行。你在文件的末尾离开了。

当然,您可能可以使用seek来回退文件句柄(假设它不是管道),但是为什么要再次从文件中读取呢?你已经在内存中拥有了整个东西,而且它也已经被解码了!把它分成几行。

 my $file_contents; { local $/; $file_contents = <$file_handle>; }

utf8::decode($file_contents)
   or die 'Not a valid UTF-8 file';

for (split /^/m, $file_contents, -1) {
    chomp;
    ...
}

或者因为你无论如何都在咀嚼,

for (split /\n/, $file_contents) {
    ...
}

我避免了do,因为它会导致在内存中创建文件的额外副本。

于 2013-05-06T19:57:13.470 回答
1

创建$fhtest. 如果你想回到开始,你可以使用seek

use Fcntl ':seek';    # import constants
...
my $fhtest      = do {
        local $/;
        <$file_handle>;
};

my $utf8;
eval { $utf8 = decode( "utf8", $fhtest, Encode::FB_CROAK | Encode::LEAVE_SRC) };
if ($@) {
        die 'Not a valid UTF-8 file';
}

seek $file_handle, 0, SEEK_SET;

# now you can start over with $file_handle

当然,由于您已经将所有数据加载到内存中$fhtest,您可以将split它放在换行符(或其他任何内容)上并循环遍历结果。或者你可以打开一个假文件句柄来处理你已经在内存中的文件:

open my $fake_fh, '<', \$fhtest;
while( <$fake_fh> ) { 
    ....
}
于 2013-05-06T19:38:18.700 回答