【问题标题】:What is the best way to write a large file to disk in PHP?在 PHP 中将大文件写入磁盘的最佳方法是什么?
【发布时间】:2011-06-15 10:38:55
【问题描述】:

我有一个偶尔需要将大文件写入磁盘的 PHP 脚本。使用file_put_contents(),如果文件足够大(在本例中约为 2 MB),PHP 脚本会耗尽内存(PHP 致命错误:允许的内存大小为 ######## 字节已用尽)。我知道我可以只增加内存限制,但这对我来说似乎不是一个完整的解决方案——必须有更好的方法,对吧?

用 PHP 将大文件写入磁盘的最佳方法是什么?

【问题讨论】:

  • 数据的来源是什么?此外,大多数 PHP 配置应该能够毫无问题地处理 2MB。您的内存限制可能远低于此限制。
  • 文件从何而来?如果它已经存在于磁盘上,那么copy() 将是最合适的。
  • 在这种情况下,我使用 curl 从远程服务器获取文件。所以,我把它放在一个变量中。
  • 跳过 curl,使用copy("http://example.com/file", "/tmp/local.txt")
  • @mario:这很容易,但我正在复制多个文件,我喜欢我可以使用 curl_multi_* 东西同时运行它们

标签: php file file-io fwrite


【解决方案1】:

您需要一个临时文件,在其中放置源文件的部分内容以及要附加的内容:

$sp = fopen('source', 'r');
$op = fopen('tempfile', 'w');

while (!feof($sp)) {
   $buffer = fread($sp, 512);  // use a buffer of 512 bytes
   fwrite($op, $buffer);
}

// append new data
fwrite($op, $new_data);    

// close handles
fclose($op);
fclose($sp);

// make temporary file the new source
rename('tempfile', 'source');

这样,source 的全部内容不会被读入内存。使用 cURL 时,您可以省略设置 CURLOPT_RETURNTRANSFER,而是添加一个写入临时文件的输出缓冲区:

function write_temp($buffer) {
     global $handle;
     fwrite($handle, $buffer);
     return '';   // return EMPTY string, so nothing's internally buffered
}

$handle = fopen('tempfile', 'w');
ob_start('write_temp');

$curl_handle = curl_init('http://example.com/');
curl_setopt($curl_handle, CURLOPT_BUFFERSIZE, 512);
curl_exec($curl_handle);

ob_end_clean();
fclose($handle);

似乎我总是错过显而易见的事情。正如 Marc 所指出的,有CURLOPT_FILE 可以直接将响应写入磁盘。

【讨论】:

  • 有道理,但在这种情况下,我使用 curl 从不同的服务器检索文件,因此它已经在内存中。
  • @Joe 我更新了答案。另一个建议来了。
  • 第一个解决方案你可能也用过stream_copy_to_stream ;-)
  • @user576875 不。为什么要轻松? :-) 开玩笑。感谢您的提示。
  • 不需要缓冲。 curl 可以使用curl_setopt('CURLOPT_FILE', ...)直接写入文件
【解决方案2】:

使用fwrite()等函数逐行写入(或在二进制文件的情况下逐包写入)

【讨论】:

    【解决方案3】:

    试试this answer:

        $file   = fopen("file.json", "w");
    
        $pieces = str_split($content, 1024 * 4);
        foreach ($pieces as $piece) {
            fwrite($file, $piece, strlen($piece));
        }
    
        fclose($file);
    

    【讨论】:

      猜你喜欢
      • 2020-12-29
      • 2020-09-01
      • 1970-01-01
      • 2010-11-08
      • 1970-01-01
      • 2014-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多