当我尝试在 PHP 中读取一个非常适中的文件时,

fopen 失败了。 一个6兆字节的文件使它窒息,但 100k 周围的小文件就好了。我已经读过有时需要使用 -D_FILE_OFFSET_BITS = 64 标志重新编译 PHP ,以便读取超过20场演出的文件或者荒谬的东西,但不应该6 meg文件没有问题?最终我们想要读取大约100兆的文件,并且能够打开它们然后逐行读取它们将很好,因为我可以使用较小的文件。

PHP 中读取和操作非常大的文件的技巧/解决方案是什么?

更新:这是一个在我的6 meg文件上失败的简单代码块的示例 - PHP似乎没有抛出错误,它只返回false。也许我正在做一些非常愚蠢的事情?

$rawfile = "mediumfile.csv";

if($file = fopen($rawfile, "r")){  
  fclose($file);
} else {
  echo "fail!";
}

另一个更新:感谢所有人的帮助,它确实是令人难以置信的愚蠢 - 权限问题。当较大的文件没有时,我的小文件莫名其妙地具有读权限。卫生署!

有帮助吗?

解决方案

你确定它的 fopen 失败而不是脚本的超时设置吗?默认值通常约为30秒左右,如果您的文件花费的时间超过了读取的时间,则可能会使文件绊倒。

要考虑的另一件事可能是脚本的内存限制 - 将文件读入数组可能会超过此值,因此请检查错误日志中的内存警告。

如果以上都不是您的问题,您可以考虑使用 fgets 逐行读取文件,随时处理。

$handle = fopen("/tmp/uploadfile.txt", "r") or die("Couldn't get handle");
if ($handle) {
    while (!feof($handle)) {
        $buffer = fgets($handle, 4096);
        // Process buffer here..
    }
    fclose($handle);
}

修改

  

PHP似乎没有抛出错误,它只返回false。

$ rawfile 的路径相对于脚本运行的位置是否正确?也许尝试在这里为文件名设置一个绝对路径。

其他提示

使用1.3GB文件和9.5GB文件进行了2次测试。

1.3 GB

使用 fopen()

此过程使用15555毫秒进行计算。

它在系统调用中花费了169毫秒。

使用 file()

此过程使用6983 ms进行计算。

它在系统调用中花了4469毫秒。

9.5 GB

使用 fopen()

此过程使用113559毫秒进行计算。

它在系统调用中花了2532毫秒。

使用 file()

此过程使用8221 ms进行计算。

它在系统调用中花费了7998毫秒。

似乎 file()更快。

如果您只想输出文件,可以尝试使用readfile函数。

如果不是这种情况 - 也许您应该考虑应用程序的设计,为什么要在Web请求上打开如此大的文件?

我使用fopen打开视频文件进行流式传输,使用php脚本作为视频流服务器,我对大小超过50/60 MB的文件没有任何问题。

• fgets()函数很好,直到文本文件传递20 MB,并且解析速度大大降低。

• file_ get_contents()函数提供了良好的结果,直到40 MB并且可接受的结果直到100 MB,但 file_get_contents()将整个文件加载到内存中 ,所以它不是scalabile。

• file()函数对于大文本文件是灾难性的,因为此函数创建一个包含每行文本的数组,因此该数组存储在内存中,使用的内存更大。
实际上,我只能设置一个200 MB的文件来解析设置为2 GB的 memory_limit ,这对于我打算解析的1+ GB文件是不合适的。

当你必须解析大于1 GB的文件并且解析时间超过15秒并且你想避免将整个文件加载到内存中时,你必须找到另一种方法。

我的解决方案是以任意小块解析数据。代码是:

$filesize = get_file_size($file);
$fp = @fopen($file, "r");
$chunk_size = (1<<24); // 16MB arbitrary
$position = 0;

// if handle $fp to file was created, go ahead
if ($fp) {
   while(!feof($fp)){
      // move pointer to $position in file
      fseek($fp, $position);

      // take a slice of $chunk_size bytes
      $chunk = fread($fp,$chunk_size);

      // searching the end of last full text line
      $last_lf_pos = strrpos($chunk, "\n");

      // $buffer will contain full lines of text
      // starting from $position to $last_lf_pos
      $buffer = mb_substr($chunk,0,$last_lf_pos);

      ////////////////////////////////////////////////////
      //// ... DO SOMETHING WITH THIS BUFFER HERE ... ////
      ////////////////////////////////////////////////////

      // Move $position
      $position += $last_lf_pos;

      // if remaining is less than $chunk_size, make $chunk_size equal remaining
      if(($position+$chunk_size) > $filesize) $chunk_size = $filesize-$position;
      $buffer = NULL;
   }
   fclose($fp);
}

使用的内存只是 $ chunk_size ,速度略小于 file_ get_contents()获得的速度。我认为PHP Group应该使用我的方法来优化它的解析功能。

*)此处找到 get_file_size()函数。

如果问题是由达到内存限制引起的,您可以尝试将其设置为更高的值(这可能有效或无效,具体取决于php的配置)。

这将内存限制设置为12 Mb

ini\_set("memory_limit","12M");

对我来说, fopen()的速度非常慢,文件超过1mb, file()要快得多。

只是尝试一次读取100行并创建批量插入, fopen()需要37秒, file()需要4秒。必须是内置于 file()

中的 string-&gt; array 步骤

我会尝试所有文件处理选项,看看哪种方法最适合您的应用程序。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top