当我尝试在fopen
中读取一个非常适中的文件时,PHP
失败了。 A 6 meg file
让它窒息,虽然100k
附近的小文件就好了。我已经读过,有时需要用PHP
标志重新编译-D_FILE_OFFSET_BITS=64
,以便读取超过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 ms进行计算。
它在系统调用中花费了169毫秒。
使用file()
此过程使用6983 ms进行计算。
它在系统调用中花费了4469毫秒。
9.5 GB
使用fopen()
此过程使用113559 ms进行计算。
它在系统调用中花费了2532毫秒。
使用file()
此过程使用8221 ms进行计算。
它在系统调用中花费了7998毫秒。
似乎file()
更快。
那么你可以尝试使用readfile函数,如果你只想输出文件。
如果不是这种情况 - 也许您应该考虑应用程序的设计,为什么要在Web请求上打开如此大的文件?
我使用fopen打开流媒体视频文件,使用php脚本作为视频流服务器,我对大小超过50/60 MB的文件没有任何问题。
•fgets()
函数很好,直到文本文件超过20 MB,并且解析速度大大降低。
•file_ get_contents()
函数提供了良好的结果,直到40 MBytes和可接受的结果,直到100 MB,但file_get_contents()
将整个文件加载到内存中,所以它不是scalabile。
•file()
函数对于大文本文件是灾难性的,因为此函数创建包含每行文本的数组,因此该数组存储在内存中,并且使用的内存更大。
实际上,一个200 MB的文件,我只能设法用memory_limit
解析,设置为2 GB,这对于我打算解析的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()
函数here。
如果问题是由达到内存限制引起的,您可以尝试将其设置为更高的值(这可能有效或无效,具体取决于php的配置)。
这将内存限制设置为12 Mb
ini\_set("memory_limit","12M");
对我来说,fopen()
的文件超过1mb非常慢,file()
要快得多。
只是尝试一次读取100行并创建批量插入,fopen()
需要37秒,而file()
需要4秒。必须是在string->array
内置的file()
步骤
我会尝试所有文件处理选项,看看哪种方法最适合您的应用程序。