2013-05-06 92 views
1

我正在嘗試檢測上傳的文件是否爲有效的UTF-8,並且僅在此之後纔對其內容進行一些操作。它檢測到非UTF-8文件正常,但如果文件是有效的UTF-8,則沒有要處理的內容。沒有要在while(){}循環中處理的數據。我的錯誤在哪裏?Perl文件上傳。如何多次訪問文件句柄?

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 ([email protected]) { 
     die 'Not a valid UTF-8 file'; 
} 

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

回答

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

當您創建$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 ([email protected]) { 
     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>) { 
    .... 
} 
+0

謝謝!第一種使用seek的方法工作正常。嘗試第二個打開假文件句柄 - 沒有數據在'while'循環中處理。那是stratnge,'$ fhtest'確實包含數據,但它不會傳遞給假的文件句柄。 – nixoid 2013-05-06 19:58:19

+0

使用'Encode :: FB_CROAK | Encode :: LEAVE_SRC'修復了這個問題。固定。 – ikegami 2013-05-06 20:16:52