我正在尝试检测上传的文件是否是有效的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
}
答案 0 :(得分:2)
当您使用readline
(又名<$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
,因为它会导致在内存中创建额外的文件副本。
答案 1 :(得分: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> ) {
....
}