2017-05-01 10 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

を扱う、中括弧を維持することを確認してください。この質問は密接なぜPerlで書かれた私のイメージのダウンロードCGIスクリプトが動作していない[に関連していますか? ](https://stackoverflow.com/q/10563275/100754)両方のコードがコピーされているように見える同じくそったチュートリアルサイトから。私のブログ記事[PerlのファイルダウンロードCGIスクリプト](https://www.nu42.com/2012/05/file-download-cgi-script-in-perl.html)も参照してください。質問。 2つの質問は、異なる理由で失敗しているため、正確な重複ではありません。 –

+0

**「最後に指定された? 『のbinmodeは』理由です」** ...ので、彼らはどちらかやっていたかわからなかった他の誰かによって書かれたチュートリアルからコピーしたコードをやっていたかわからなかった誰か。実のところ、実際のファイルハンドルは 'DLFILE'なので、' binmode'ing '$ DLFILE'はどこに置かれても何もしません。人生の唯一の目的は、スクリプトを書いた無能な人が「厳格な」使用をしていないことを示すことです。 –

+0

この*ばかげた* 14歳のスクリプト: 'https:// www.sitepoint.com/file-download-script-perl /' –

答えて

5

私はbinmode $DLFILEが何のためにあるのか見当がつかない。 $DLFILEは、ファイルハンドルDLFILEとは何の関係もありません、それは今では最後に読み込まれたことを、ファイルののbinmodeを設定するために少し遅れます。これはおそらく、あなたが代わりにこれを使用することができますちょうど間違い

です。それは、現代のPerlベストプラクティスを使用して読み込み、ファイル名はので、私は$nameが正しいだろうということはよく分からない$IDから作られているように見える8Kチャンク

でファイルを送信しますが、私は

を伝えることはできませんブロックは、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

答えは事実ですが、ここではそのような解決策を探し、誰(例えば初心者は)* *正確 'ローカルの$/= \(* 1024年8を)何をするか理解できないだろう;'(特に '\('部分)。 。。。私はそれが少し異なるものといくつかの簡単な説明は、(単なる私見) – jm666

+0

親愛なるボロディン、おかげであなたの答えのためにたくさんいいだろうが、私はそれが最終的に私がやったと同じだと思う?(読みながら($ FH、私の$ bufは、* 1024 64)){印刷$ bufを;} –

+0

PSこれを読んで、誰のための別の改善: 私の$ファイルサイズ= -s $ files_location;印刷 "のContent-Length:$のファイルサイズの\ 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