我正在尝试将外部API中的大文件传递给用户(想想100MB或更多)
目前,我正在使用一些偏执的脚本(由于过去的失败)来尽快下载脚本。
通过'下载',我只是指浏览器上的下载触发器,而不是文件的实际下载。只是用户可以选择他想要保存文件的位置。
set_time_limit(0);
apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 0);
ini_set('output_buffering', 0);
ini_set('implicit_flush', 1);
for($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);
header('Content-Description: File Transfer');
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: private');
ob_flush();
flush();
$fh = fopen($external_api_url, 'rb');
while(!feof($fh))
{
echo fread($fh, 512);
ob_flush();
flush();
}
fclose($fh);
使用此脚本,在下载弹出窗口显示之前,50mb文件仍然需要20秒,而对于更大的文件,则需要更长时间。
有没有办法更快地启动流?
编辑: 我也尝试了fpassthru()和readfile(),但这些相同的50mb文件需要40秒,这让我觉得这样更好。我也玩了不同的读取大小(512,256,64,其他几个),但我没有注意到差异)
答案 0 :(得分:0)
浏览器花费这么长时间来触发下载对话框的原因是由于API需要很长时间才能返回其第一块数据,例如他们可能在开始发送之前将整个文件读取到内存中给你的数据,这可以解释为什么更长的文件需要更长的时间才能启动,即使你总是尝试尽可能快地写入前512个字节。
我试图通过从本地文件中读取来本地模拟它,但在sleep(5);
循环之前发出while
语句。
我可以让谷歌浏览器开始下载任何数据,省略 header('Content-type: application/octet-stream');
行,同时在尝试阅读之前仍然发出flush();
来电文件。 (你已经在做第二部分了)
然而,这似乎不适用于Firefox 3.6,因此您可能需要针对不同浏览器使用不同的噱头,除非您可以预测文件的第一个字符(请查看BOM)并在之前回复任何事情,随后从您第一次fread()
电话的开头删除它。
我希望它有所帮助!但基本上外部API会让你失望。