2017-05-01 35 views
-1

下面的代碼是我們正在使用的Perl CGI腳本的原始代碼。即使對於非常大的文件,它似乎也能正常工作,但對於非常大的文件卻不適用。通過HTTP提供非常大的二進制文件時內存不足

當前的代碼是:

$files_location = $c->{target_dir}.'/'.$ID; 
open(DLFILE, "<$files_location") || Error('open', 'file'); 
@fileholder = <DLFILE>; 
close (DLFILE) || Error ('close', 'file'); 

print "Content-Type:application/x-download\n"; 
print "Content-Disposition:attachment;filename=$name\n\n"; 
print @fileholder; 
binmode $DLFILE; 

如果我理解正確的代碼,它加載在內存中的整個文件「打印」之前。當然,我認爲加載並按塊顯示會好很多。但在閱讀了很多論壇和教程後,我仍然不確定如何最好地使用標準Perl庫...

最後一個問題,爲什麼在末尾指定了「binmode」?

非常感謝任何提示或建議,

+0

這個問題是密切相關[爲什麼我的圖像下載CGI腳本用Perl編寫不工作? ](https://stackoverflow.com/q/10563275/100754),因爲兩者中的代碼似乎都已被複制來自同一個蹩腳的教程網站。另請參閱我的博客文章[文件下載Perl中的CGI腳本](https://www.nu42.com/2012/05/file-download-cgi-script-in-perl.html)題。這兩個問題並不完全重複,因爲它們因不同原因而失敗。 –

+0

**「爲什麼」binmode「最後指定?」** ...因爲不知道他們在做什麼的人從其他人不知道他們在做什麼的教程中複製代碼。事實上,由於實際的文件句柄是'DLFILE',因此無論如何,'bin_ode'ing'$ DLFILE'都不會做任何事情,無論它放在哪裏。它唯一的目的是要表明寫劇本的無能的人不會「嚴格地使用」。 –

+0

這個*笨的* 14歲的腳本:'https://www.pointpoint.com/file-download-script-perl /' –

回答

5

我不知道binmode $DLFILE是什麼。 $DLFILE與文件句柄DLFILE無關,現在設置文件的binmode已經讀完爲止有點晚了。這可能只是一個錯誤

你可以用它來代替。它採用現代Perl的最佳做法,並讀取和發送在8K的塊

文件名似乎來自$ID製成,所以我不知道,$name將是正確的文件,但我不能告訴

請一定要保持大括號,如塊使Perl的恢復$/舊值並關閉打開的文件句柄

my $files_location = "$c->{target_dir}/$ID"; 

{ 
    print "Content-Type: application/x-download\n"; 
    print "Content-Disposition: attachment; filename=$name\n\n"; 

    open my $fh, '<:raw', $files_location or Error('open', "file $files_location"); 
    local $/ = \(8 * 1024); 

    print while <$fh>; 
} 
+3

雖然答案是正確的,但任何在這裏尋找這種解決方案的人(例如初學者)*都不會理解「本地$/= \(8 * 1024)」(特別是'\('部分))究竟是什麼。 (只是恕我直言) – jm666

+0

親愛的鮑羅廷,非常感謝你的回答,我做了一點不同,但我認爲最後它是一樣的嗎?我做了:while(read($ fh,my $ buf,64 * 1024)){print $ buf;} –

+0

PS對於讀者來說,另一個改進是: my $ filesize = -s $ files_location; print「Content-Length:$ filesize \ n」; –

3

你拉動整個文件一次到內存中。最好循環逐行掃描文件,這樣可以消除這個問題。

另請注意,我修改了代碼以使用正確的3-arg open,並且使用詞法文件句柄代替全局空白句柄。

open my $fh, '<', $files_location or die $!; 

print "Content-Type:application/x-download\n"; 
print "Content-Disposition:attachment;filename=$name\n\n"; 

while (my $line = <$fh>){ 
    print $line; 
} 

binmode調用似乎是在你這裏顯示什麼情況下無用的,因爲$DLFILE不似乎是一個有效的,在使用的變量(在頂部添加use strict;use warnings;您腳本...)

+2

1.二進制文件沒有行。最好將'$ /'設置爲'\(64 * 1024)'或其他。 2.濫用'binmode'的解決方法是正確使用它,而不是消除它。要麼添加'binmode($ fh);',要麼使用'<:raw'而不是''。 – ikegami

相關問題