<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://jackxiang.com/post//</link>
<title><![CDATA[PHP读取大文件大小的方法---注意fgets()指针越界.]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Mon, 13 Sep 2010 07:21:26 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	string fgets ( int $handle [, int $length ] )<br/>从 handle 指向的文件中读取一行并返回长度最多为 length - 1 字节的字符串。碰到换行符（包括在返回值中）、EOF 或者已经读取了 length - 1 字节后停止（看先碰到那一种情况）。如果没有指定 length ，则默认为 1K，或者说 1024 字节。 <br/>bool feof ( resource $handle )<br/>果传递的文件指针无效可能会陷入无限循环中，因为 EOF 不会返回 TRUE。<br/>先上代码，正确的写法：<br/>指针位置文件：line_number_mark.txt，需要读取N行的大文件：onlyQQFilteredByJack.txt<br/><div class="code"><br/>&lt;?php<br/>$num = 0;<br/>$insert_num = 10; //insert amount every time.<br/>if(file_exists(&#039;line_number_mark.txt&#039;))<br/>&#123;<br/>$num = trim(file_get_contents($rootPath . &#039;line_number_mark.txt&#039;));<br/>&#125;<br/>echo &quot;pointer_num=&quot;.$num.&quot;&#92;n&quot;;<br/>$fp = fopen(&#039;./onlyQQFilteredByJack.txt&#039;, &#039;r&#039;);<br/>fseek($fp, $num);<br/>$i = 0;<br/>while($i &lt; $insert_num)<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;if(!feof($fp))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data = fgets($fp);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$value = trim($data);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!empty($value))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i++;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo $value.&quot;&#92;n&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;else<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;out of the file&#039;s bindery,exit the while loop..&#92;n&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$position = ftell($fp);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$flag = 1;//set flag means it&#039;s already end<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;//Break 退出循环<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/>if($flag)<br/>file_put_contents($rootPath . &#039;line_number_mark.txt&#039;, $position);<br/>else<br/>file_put_contents($rootPath . &#039;line_number_mark.txt&#039;, ftell($fp));<br/>?&gt;<br/></div><br/>指针的越位，错误的写法：<br/>&lt;?php<br/>$num = 0;<br/>$insert_num = 10; //insert amount every time.<br/>if(file_exists($rootPath . &#039;line_number_mark.txt&#039;))<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$num = trim(file_get_contents($rootPath . &#039;line_number_mark.txt&#039;));<br/>&#125;<br/>echo &quot;num=&quot;.$num.&quot;&#92;n&quot;;<br/>$fp = fopen($rootPath . &#039;onlyQQFilteredByJack.txt&#039;, &#039;r&#039;);<br/>fseek($fp, $num);<br/>echo ftell($fp).&quot;&#92;n&quot;;<br/>if(feof($fp))<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Out of the file&#039;s bond&#92;n&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit();<br/>&#125;<br/>$i = 0;<br/>while($i &lt; $insert_num)<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$data = fgets($fp);//没fget一次，指针自动加一，后面ftell的值也是加一后的值，而在while下造成了越界，下次在来读取后在上面的if(feof($fp))出现传递的文件指针无效可能会陷入无限循环中，因为 EOF 不会返回 TRUE。<br/>&nbsp;&nbsp;&nbsp;&nbsp;$value = trim($data);<br/>&nbsp;&nbsp;&nbsp;&nbsp;if(!empty($value))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i++;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo $value.&quot;&#92;n&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/>echo ftell($fp).&quot;&#92;n&quot;;<br/>file_put_contents($rootPath . &#039;line_number_mark.txt&#039;, ftell($fp));<br/>?&gt;<br/><br/>回忆未来(372647693)&nbsp;&nbsp;14:52:20<br/>PHP读取大文件，一次读取，php的内存往往不够用，大家如何解决类似的问题？<br/>膘叔(19129540)&nbsp;&nbsp;14:52:51<br/>那就别一次读。<br/>莫莫(3296320)&nbsp;&nbsp;14:53:24<br/>用fopen<br/>莫莫(3296320)&nbsp;&nbsp;14:53:30<br/>然后一点一点移指针<br/>PHP内置函数filesize()返回文件的长度是int类型的，按照PHP文档上的sprintf(&#039;%u&#039;, filesize($str_filename))，最大也只能正确表示不大于2748436857字节（约2.6GB）。解决办法有不少，整理了最通用的办法如下：<br/>在本例中， $int_filesize实际上是以浮点型存储的，但应理解为整数<br/>Linux系统<br/>$int_filesize = 0 + trim(`stat -c%s $str_file`);<br/>Windows系统<br/>$int_size = 0 + exec(&#039;FOR %A IN (&quot;&#039;. $str_file.&#039;&quot;) DO @ECHO %~zA&#039;);<br/>完整函数<br/>function big_filesize($str_filename)<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$int_filesize = filesize($str_filename);<br/>&nbsp;&nbsp;&nbsp;&nbsp;if($int_filesize &lt; 0)&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(strtolower(substr($_SERVER[&#039;OS&#039;], 0, 3)) == &#039;win&#039;)&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$int_size = 0 + exec(&#039;FOR %A IN (&quot;&#039;. $str_file.&#039;&quot;) DO @ECHO %~zA&#039;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;else&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$int_filesize = 0 + trim(`stat -c%s $str_file`);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;return $int_filesize;<br/>&#125;<br/>最近在工作中遇到了需要读取系统日志的问题，日志文件很大，大概在1G以上甚至更大，随即研究了读取得方法，直接使用PHP自带的函数就可以解决这几个问题，但是绝对不能使用file和file_get_contents，这两个函数是一次性将文件全部加载进来，如果文件在几十M 还是可以的，但是稍大的文件时不能用的，内存是会溢出的，贴个自己的方法，欢迎大家指教！ <br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
function readBigFile($filename, $count = 20, $tag = &quot;&#92;r&#92;n&quot;) &#123;
$content = &quot;&quot;;//最终内容
$current = &quot;&quot;;//当前读取内容寄存
$step= 1;//每次走多少字符
$tagLen = strlen($tag);
$start = 0;//起始位置
$i = 0;//计数器
$handle = fopen($filename,&#039;r+&#039;);//读写模式打开文件，指针指向文件起始位置
while($i &lt; $count &amp;&amp; !feof($handle)) &#123;
fseek($handle, $start, SEEK_SET);//指针设置在文件开头
$current = fread($handle,$step);//读取文件
$content .= $current;//组合字符串
$start += $step;//依据步长向前移动
//依据分隔符的长度截取字符串最后免得几个字符
$substrTag = substr($content, -$tagLen);
if ($substrTag == $tag) &#123; //判断是否为判断是否是换行或其他分隔符
$i++;
$content .= &quot;&lt;br /&gt;&quot;;
&#125;
&#125;
//关闭文件
fclose($handle);
//返回结果
return $content;
&#125;
$filename = &quot;E:&#92;电影目录&#92;Jobs.2013.720p.HDRip.AC3.H264-N.E.T.ism.mkv&quot;;//需要读取的文件
$tag = &quot;&#92;n&quot;;//行分隔符 注意这里必须用双引号
$count = 100;//读取行数
$data = readBigFile($filename,$count,$tag);
echo $data;

?&gt;
</textarea><br/><br/>关于函数传入的变量$tag的值，根据系统不一样，传入的值也是有区别的：Windows用”&#92;r&#92;n”，linux/unix用”&#92;n”，Mac OS用”&#92;r”。 <br/><br/>程序执行的大概流程：先定义读取文件的一些基础变量，然后打开文件，将指针定位在文件的指定位置，并读取指定大小的内容。每读取一次将内容存储在变量中，直到达到读取要求的行数或文件结束。 <br/><br/>绝不要假定程序中的一切都将按计划运行。 <br/><br/>根据上面的代码，虽然能够得到文件中指定位置、指定大小的数据，但这整个过程只执行了一次，并不能得到所有的数据。其实要得到所有的数据，可以在这个循环的外层再添加判断文件是否结束的循环，但这很浪费系统资源，甚至由于文件过大一直没法读完而导致PHP执行超时。另一种方法就是记录并存储上次读取数据后指针所在的位置，然后再次执行该循环的时候，将指针定位在上次结束的位置，这样就不存在一次循环要把文件从头读到尾的情况。 <br/><br/><br/>PHP还有其他方法能够解决，比如system函数，不足之处还望指正！<br/>最近碰到一个比较有趣的问题，就是修改某个文件的某一行字符，不过文件太大，file()直接读取是不可能的，我使用fgets来跳转到指定行，并用fwrite修改某个字符串：&lt;/p&gt;<br/>$fp = fopen(&#039;d:/file.txt&#039;, &#039;r+&#039;);<br/>if ($fp) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$i = 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;while (!feof($fp)) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//修改第二行数据<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($i == 2) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fseek($fp, 2, SEEK_CUR);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwrite($fp, &#039;#&#039;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fgets($fp);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i++;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;fclose($fp);<br/>&#125;<br/>这里需要注意的是fgets获取到一行后，文件指针指向行尾(也就是下一行开头)，所以fwrite操作的是fgets后的下一行开头，至于从该行的第几个字符开始写，可以使用fseek函数来移动文件指针。另外一个需要注意的是，这里fwrite写入是执行替换操作，而不是插入操作，所以指针后面的字符会一个个被替换掉。至于怎么插入我就没研究了。估计很困难。为了效率可能只能写入另外一个临时文件了，不知道有没有其他更好的方法。<br/>另外今天还看到了使用SPL进行操作的方法：<br/>$fp = new SplFileObject(&#039;d:/file.txt&#039;, &#039;r+&#039;);<br/>//转到第二行, seek方法参数从0开始计数, 经我测试指针指向行尾了, 所以修改的是第三行<br/>$fp-&gt;seek(1);<br/>//获取当前行内容(第二行)<br/>$line = $fp-&gt;current();<br/>//下面是对第三行的操作<br/>$fp-&gt;fseek(2, SEEK_CUR);<br/>$fp-&gt;fwrite(&#039;#&#039;);<br/>　SplFileObject提供的方法比基本的文件操作函数更丰富一些，包括采用key/value方法遍历文件行等。SPL应该是PHP5增加进去的吧，还有其他很多很有用的对象。包括数组、文件目录操作、异常处理、一些基本类型操作等，这些功能还在陆续增加，可以通过继承SPL扩展这些方法让我们处理底层的操作更方便。<br/><div class="code">&lt;?php<br/>$fp= new SplFileObject(&#039;testfile.txt&#039;);<br/>$fp-&gt;seek(1);<br/>$line = $fp-&gt;current();<br/>echo $line;<br/>$fp-&gt;seek(881);<br/>$line = $fp-&gt;current();<br/>echo $line;<br/>$fp-&gt;seek(123456);<br/>$line = $fp-&gt;current();<br/>echo $line;<br/>?&gt;</div><br/>读取到末尾的判断：$fp-&gt;eof()<br/><div class="code">$fp = new SplFileObject(&#039;./chat.txt&#039;, &#039;r+&#039;);&nbsp;&nbsp;<br/>$line = 0;&nbsp;&nbsp;<br/>$totalLine = 0;&nbsp;&nbsp;<br/>while (!$fp-&gt;eof()) &#123;&nbsp;&nbsp;<br/>$fp-&gt;current();&nbsp;&nbsp;<br/>$totalLine++;&nbsp;&nbsp;<br/>$fp-&gt;next();&nbsp;&nbsp;<br/> &#125;&nbsp;&nbsp;<br/>$fp-&gt;seek($totalLine);</div><br/><div class="code">&lt;?php<br/>$fp = new SplFileObject(&#039;./file.txt&#039;, &#039;r+&#039;);<br/>//转到第二行, seek方法参数从0开始计数, 经我测试指针指向行尾了, 所以修改的是第三行<br/>$fp-&gt;seek(1);<br/>////获取当前行内容(第二行)<br/>$line = $fp-&gt;current();<br/>echo $line;<br/>////下面是对第三行的操作<br/>$fp-&gt;fseek(2, SEEK_CUR);<br/>$fp-&gt;fwrite(&#039;#jackxiang&#039;);<br/>?&gt;</div><br/>来源：http://www.cnblogs.com/gaocheng/articles/1778499.html<br/>http://www.php100.com/html/webkaifa/PHP/PHPyingyong/2009/1029/3453.html
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] PHP读取大文件大小的方法---注意fgets()指针越界.]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>