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

相关问题