PHP读取1GB文件的方便内存限制应该是多少?

3

我有一个1GB的文件1需要读取。我选择使用php筛选和更改一些行,然后创建另一个文件2来保存这些更改。代码很好。如果我读取50MB的文件,它可以良好地工作。代码生成了一个包含所有更改的文件2,如预期所示。但是当我尝试运行1GB的文件时,文件2没有被创建,我从浏览器中得到了以下错误信息:

The connection to localhost was interrupted.
Check your Internet connection
Check any cables and reboot any routers, modems, or other network devices you may be using.
Allow Chrome to access the network in your firewall or antivirus settings.
If it is already listed as a program allowed to access the network, try removing it from the list and adding it again.
If you use a proxy server...
Check your proxy settings or contact your network administrator to make sure the proxy server is working. If you don't believe you should be using a proxy server: Go to the Chrome menu > Settings > Show advanced settings... > Change proxy settings... > LAN Settings and deselect "Use a proxy server for your LAN".

如果我返回并运行小文件,它会再次正常工作。 我已经将php内存设置为2040M ini_set('memory_limit', '2048M'),但我不知道是否足够或者是否可能出问题。
那么,对于这个问题,应该使用多大的内存比较合适呢?
注意:服务器是Apache,Win7,i7 8核64位,16G RAM。 我认为代码并不重要,但有人要求查看它:
                       ini_set('memory_limit', '2048M');#Set the memory limit
                              $new_dbName="au_site";
                              $patern[0]="/di_site/";
                              $replace[0]=$new_dbName;
                              #xdebug_break();
                              $dirBase=dirname(__FILE__);
                              $dir2 = new DirectoryIterator(dirname(__FILE__));
                              #xdebug_break();
                              foreach ($dir2 as $fileinfo) {
                                     if (!$fileinfo->isDot() && $fileinfo->isFile()) {
                                          $str = $fileinfo->getFilename();
                                          if (preg_match("/\.sql/i", $str)) {
                                               #xdebug_break();
                                               $i=1;
                                               if(!($handle= fopen("$str", "r"))){

                                                die("Cannot open the file");
                                               }
                                               else{
                                                     while (!feof($handle)) {   
                                                             #xdebug_break();
                                                             $line=trim(fgets($handle), "\t\n\r\0\x0B");
                                                             $firstChar =  substr($line, 0,1) ;
                                                             $ord = ord($firstChar);
                                                             if(ord($firstChar)<>45){
                                                               if (preg_match("/di_site/", $line)) {
                                                                xdebug_break();
                                                                   $chn=preg_replace($patern, $replace, $line); 
                                                                   $line=$chn;
                                                               }
                                                               #echo $line."<br>";
                                                               $sql.=$line."\n";
                                                             }                                                            
                                                      }
                                                      xdebug_break();
                                                      $newDBsql=$dirBase."/".$new_dbName.".sql";
                                                      if(!$handle =  fopen($newDBsql,"w")){
                                                           die("Can not open the file");
                                                      }
                                                      else{
                                                       fwrite($handle, $sql);
                                                       fclose($handle);
                                                      }

                                               }
                                            } 
                                     }
                               } 

这可能会有所帮助:https://dev59.com/53VC5IYBdhLWcg3w21Eq 建议使用fget逐行读取文件。 - Mehdi
有代码吗?还是让我们猜测? - user557846
文件太大了。浏览器超时了。我认为默认时间是30秒。 - ksealey
嗨 Dragon,我认为代码并不重要。对于小文件,它的工作效果很好。 - IgorAlves
1
“几MB”?您需要一次性读/写文件,还是可以顺序解析/生成它?因为磁盘上的文件大小与您需要在内存中执行所需的字节数量无关。 - Mike 'Pomax' Kamermans
显示剩余4条评论
1个回答

2

不要构建整个文件内容(这需要大量内存),考虑编写流过滤器

流过滤器在基础流的单个缓冲读取上运行,通常为约8KB的数据。以下示例代码定义了这样的过滤器,它将每个桶分成单独的行并调用您的代码进行更改。

<?php

class myfilter extends \php_user_filter
{
  private $buffer; // internal buffer to create data buckets with

  private $pattern = ['/di_site/'];
  private $replace = ['au_site'];

  function filter($in, $out, &$consumed, $closing)
  {
    while ($bucket = stream_bucket_make_writeable($in)) {
      $parts = preg_split('/(\n|\r\n)/', $bucket->data, -1, PREG_SPLIT_DELIM_CAPTURE);
      $buffer = '';
      // each line spans two array elements
      for ($i = 0, $n = count($parts); $i + 1 < $n; $i += 2) {
        $line = $parts[$i] . $parts[$i + 1];
        $buffer .= $this->treat_line($line);
        $consumed += strlen($line);
      }
      stream_bucket_append($out, stream_bucket_new($this->stream, $buffer));
    }
    return PSFS_PASS_ON;
  }

  /** THIS IS YOUR CODE **/
  function treat_line($line)
  {
    $line = trim($line, "\t\n\r\0\x0B");
    $firstChar =  substr($line, 0,1) ;
    if (ord($firstChar)<>45) {
      if (preg_match("/di_site/", $line)) {
        $line = preg_replace($this->pattern, $this->replace, $line);
      }
    }
    return $line . "\n";
  }

  function onCreate()
  {
    $this->buffer = fopen('php://memory', 'r+');
  }

  function onClose()
  {
    fclose($this->buffer);
  }
}

stream_filter_register("myfilter", "myfilter");

// open input and attach filter
$in = fopen(__FILE__, 'r');
stream_filter_prepend($in, 'myfilter');
// open output stream and start copying
$out = fopen('php://stdout', 'w');
stream_copy_to_stream($in, $out);

fclose($out);
fclose($in);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接