<span 本文环境: OS:Mac OS X </span>10.8.4<span PHP:</span>5.3.15
PHP的官方手册中,函数feof()下面的讨论不少,对此做了一些相关的测试。
<span 1</span> <?<span php </span><span 2</span> <span print</span> <<<<span EOF </span><span 3</span> <!DOCTYPE html> <span 4</span> <html> <span 5</span> <head> <span 6</span> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <span 7</span> <title>测试PHP中的feof()函数效果</title> <span 8</span> </head> <span 9</span> <body> <span 10</span> <div> <span 11</span> <span EOF; </span><span 12</span> <span 13</span> <span function</span> bool2str(<span $bool</span><span ) { </span><span 14</span> <span if</span> (<span $bool</span> == <span TRUE</span><span ) { </span><span 15</span> <span return</span> "TRUE"<span ; </span><span 16</span> } <span else</span><span { </span><span 17</span> <span return</span> "FALSE"<span ; </span><span 18</span> <span } </span><span 19</span> <span } </span><span 20</span> <span 21</span> <span /*</span> <span 22</span> <span * 请随便创建一个文件。 </span><span 23</span> <span * 比如:本测试中,在脚本文件的相同路径下创建了一个文本文件, </span><span 24</span> <span * 文件内容为“abcdefg”,文件名为“7bytesfile”。 </span><span 25</span> <span */</span> <span 26</span> <span $filename</span> = './7bytesfile'<span ; </span><span 27</span> <span $handle</span> = <span fopen</span>(<span $filename</span>, 'r'<span ); </span><span 28</span> <span if</span> (!<span $handle</span><span ) { </span><span 29</span> <span die</span>("文件打开失败"<span ); </span><span 30</span> <span } </span><span 31</span> <span 32</span> <span for</span>(<span $i</span> = 0; <span $i</span> <= <span filesize</span>(<span $filename</span>); <span $i</span>++<span ) { </span><span 33</span> <span fseek</span>(<span $handle</span>, <span $i</span><span ); </span><span 34</span> <span echo</span> "文件位置" . <span ftell</span>(<span $handle</span>) . ":<br />\n"<span ; </span><span 35</span> <span echo</span> "执行fseek,尚未执行读取操作之前,feof结果:" . bool2str(<span feof</span>(<span $handle</span>)) . "<br />\n"<span ; </span><span 36</span> <span echo</span> "当前位置字符:" . <span fgetc</span>(<span $handle</span>) . "<br />\n"<span ; </span><span 37</span> <span echo</span> "执行文件读取操作之后,feof结果:" . bool2str(<span feof</span>(<span $handle</span>)) . "<hr />\n"<span ; </span><span 38</span> <span } </span><span 39</span> <span /*</span> <span 40</span> <span * 通过上面一段代码可以观察到, </span><span 41</span> <span * 随着循环的执行,文件指针从文件头一直移动到文件末尾。 </span><span 42</span> <span * 但是当完成了字符“g”的读取输出,文件指针继续向后移动,这是feof()依然返回False。 </span><span 43</span> <span * 只有当执行了一次fgetc()操作之后,才返回true,表示到达文件末尾。 </span><span 44</span> <span */</span> <span 45</span> <span 46</span> <span echo</span> "ftell()结果:". <span ftell</span>(<span $handle</span>). "<hr />\n"<span ; </span><span 47</span> <span //</span><span 输出一下,很郁闷的发现文件指针的位置还是7。+_+</span> <span 48</span> <span 49</span> <span fseek</span>(<span $handle</span>, 4<span ); </span><span 50</span> <span echo</span> "文件位置" . <span ftell</span>(<span $handle</span>) . ":<br />\n"<span ; </span><span 51</span> <span echo</span> "执行fseek,尚未执行读取操作之前,feof结果:" . bool2str(<span feof</span>(<span $handle</span>)) . "<br />\n"<span ; </span><span 52</span> <span echo</span> "当前位置字符:" . <span fgetc</span>(<span $handle</span>) . "<br />\n"<span ; </span><span 53</span> <span echo</span> "执行文件读取操作之后,feof结果:" . bool2str(<span feof</span>(<span $handle</span>)) . "<hr />\n"<span ; </span><span 54</span> <span 55</span> <span fseek</span>(<span $handle</span>, 7<span ); </span><span 56</span> <span echo</span> "文件位置" . <span ftell</span>(<span $handle</span>) . ":<br />\n"<span ; </span><span 57</span> <span echo</span> "执行fseek,尚未执行读取操作之前,feof结果:" . bool2str(<span feof</span>(<span $handle</span>)) . "<br />\n"<span ; </span><span 58</span> <span echo</span> "当前位置字符:" . <span fgetc</span>(<span $handle</span>) . "<br />\n"<span ; </span><span 59</span> <span echo</span> "执行文件读取操作之后,feof结果:" . bool2str(<span feof</span>(<span $handle</span>)) . "<hr />\n"<span ; </span><span 60</span> <span fclose</span>(<span $handle</span><span ); </span><span 61</span> <span //</span><span 再次移动文件指针,效果依旧。 </span><span 62</span> <span //再用另外一段代码测试一下:</span> <span 63</span> <span 64</span> <span $handle</span> = <span fopen</span>(<span $filename</span>, 'r'<span ); </span><span 65</span> <span if</span> (!<span $handle</span><span ) { </span><span 66</span> <span die</span>("文件打开失败"<span ); </span><span 67</span> <span } </span><span 68</span> <span while</span> (!<span feof</span>(<span $handle</span><span )) { </span><span 69</span> <span $char</span> = <span fgetc</span>(<span $handle</span><span ); </span><span 70</span> <span if</span> (<span $char</span> === <span FALSE</span><span ) { </span><span 71</span> <span echo</span> 'FALSE'<span ; </span><span 72</span> } <span else</span><span { </span><span 73</span> <span echo</span> <span $char</span><span ; </span><span 74</span> <span } </span><span 75</span> <span } </span><span 76</span> <span fclose</span>(<span $handle</span><span ); </span><span 77</span> <span //</span><span 依然是输出了字符g之后,再次执行读取操作,才终止循环。</span> <span 78</span> <span 79</span> <span print</span> <<<<span EOF </span><span 80</span> </div> <span 81</span> </body> <span 82</span> </html> <span 83</span> <span EOF; </span><span 84</span> ?>
针对这种情况的猜测是,在PHP中,feof()的实现方式并非直接检查文件指针相对于文件的位置,而是根据某个标识返回结果。每次fseek()之后都会都会把这个标识设置为“False”,只有当执行一次文件内容读取操作之后,才会根据文件读取的结果对标识进行设置。
根据这种猜测,可以使用两种代码逻辑。
一个方法是不做feof()检测,直接检测内容读取函数(比如fgetc()、fgets())的执行结果。
<span 1</span> <span while</span> ((<span $content</span> = <span fgets</span>(<span $fileHandle</span><span )) !==FALSE) { </span><span 2</span> <span //</span><span 文件内容处理…… </span> <span 3</span> }
这种处理办法,利用了PHP被诟病的函数返回方式,所以得用“===”或“!==”进行检测,不能把代码简化成:
<span while</span> (<span $content</span> = <span fgets</span>(<span $fileHandle</span>)) {}
另外一个方法是先进行一次文件读取,然后再进入feof()循环:
<span 1</span> <span $content</span> = <span fgets</span>(<span $fileHandle</span><span ); </span><span 2</span> <span while</span> (!<span feof</span>(<span $fileHandle</span><span )) { </span><span 3</span> <span //</span><span 处理文件内容……</span> <span 4</span> <span $content</span> = <span fgets</span>(<span $fileHandle</span><span ); </span><span 5</span> }
经过测试,似乎前一种方法效率会高一些。