【问题标题】:If while sending a file with "readfile" I modify the file, will the download fail?如果在发送带有“readfile”的文件时我修改了文件,下载会失败吗?
【发布时间】:2011-06-16 14:35:33
【问题描述】:

如果我使用readfile() 向浏览器发送一个大(200mb)文件,并且当用户下载我修改文件时,下载会成功完成吗?如果不是 - 我如何修改不断下载的大文件?

【问题讨论】:

  • 取决于您进行修改的位置/时间 - 在用户已经获得字节后覆盖文件开头附近的一些字节不会影响下载。在当前下载点之前+之后更改字节将导致文件损坏。如果浏览器严格遵守它收到的原始 Content-length 标头,则在末尾添加一些字节可能不会显示。

标签: php apache http memory file-io


【解决方案1】:

不,如果直接编辑文件数据,它不会成功完成。将收到损坏的文件。

不过……

在 Linux 中,如果您 rmmv 一个文件,任何已经打开该文件的程序都将继续访问它。只有关闭文件后,文件才会完全释放。因此,您可以通过以下步骤安全地编辑您的大文件:

  1. 将文件复制到一个临时名称。
  2. 编辑文件。
  3. rm file_being_downloaded; mv new_file file_being_downloaded;

我尚未对此进行测试,但这应该允许所有下载 200mb 文件的人完整地接收他们的副本,并且新的下载者将获得您的更新版本。

【讨论】:

  • php的'unlink()'是否在内部使用'rm'?
  • Linux 文件系统实际上是“取消链接”一个文件。准确地说,PHP 的unlink() 实际上是在调用unlink() 系统调用,rm 也是如此。
  • 我很好奇 PHP 的 readfile() 是否真的在整个读取过程中保持文件打开,所以我查看了 PHP 源代码。确实如此。 C 代码实际上看起来像这样的 PHP 等效代码:$fp = fopen(); if ($fp) { fpassthru($fp); fclose($fp); }(PHP v5.3.6,source ext/standard/file.c,第 1484-1489 行)。如果这按您的意愿工作,我仍然非常感兴趣。如果您测试它,请报告。
  • 我现在无法测试,但我会尝试在几天内完成
  • 只是为了跟进,这行得通吗?我也从未测试过它,但我很想知道即将推出的文件管理器项目。
【解决方案2】:

我无法对此进行测试,但很可能下载会损坏,readfile() 将返回 false 并引发错误。另一种选择,iff readfile() locks 文件是在文件完成读取之前您将无法写入文件 - 我不这么认为不过确实如此。

如果我是你,我会复制文件,提供它然后删除它。您可能还想将文件内容加载到内存中并提供服务,但对于 200MB 的文件,这将是不切实际的...

$file = '/path/to/file.200mb';
$temp = tempnam(sys_get_temp_dir(), time() . '_');

copy($file, $temp);    
readfile($temp);    
unlink($temp);

【讨论】:

  • @barin:用两种可能的解决方案更新了我的答案。
  • 我不太明白你所说的“复制文件,提供它然后删除它”是什么意思 - 你能详细说明一下吗?
  • @barin:我的意思是复制文件,检查我的更新以获取一些示例代码。
  • 不错的解决方案。但是每次下载都复制一个文件真的可行吗?
  • @barin:这取决于您的具体用法,但我认为是这样。最后,您必须始终将文件复制到磁盘或内存中...@jimp 解决方案似乎更好一些,但我怀疑它是否会按预期工作。
【解决方案3】:

我会说这取决于下载的处理方式。

如果文件被保存到服务器上单独的内存位置,而您修改了实际文件。看到用户正在尝试将文件下载到备用内存位置,它应该不会影响它。

【讨论】:

  • readfile() 直接刷新输出,它不会将整个文件加载到内存中。
【解决方案4】:

最好的办法是创建一个新文件,然后更新代码以加载新文件。这样,正在下载旧文件的用户将继续这样做,但您将能够转换到新文件。

【讨论】:

    猜你喜欢
    • 2019-02-24
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 2013-10-06
    • 2021-01-13
    • 2022-01-01
    • 1970-01-01
    相关资源
    最近更新 更多