fopen
中读取一个非常适中的文件时, PHP
失败了。虽然A 6 meg file
周围的小文件很好,100k
会让它变得窒息。我已经读过有时需要用PHP
标志重新编译-D_FILE_OFFSET_BITS=64
以便读取超过20场演出的文件或者荒谬的东西,但是对于6兆字节的文件我不应该没有问题吗?最终我们想要读取大约100兆的文件,并且能够打开它们然后逐行读取它们将很好,因为我可以使用较小的文件。
您在PHP
中对非常大的文件进行阅读和操作的技巧/解决方案是什么?
更新:这是一个在我的6 meg文件上失败的简单代码块的示例 - PHP似乎没有抛出错误,它只返回false。也许我正在做一些非常愚蠢的事情?
$rawfile = "mediumfile.csv";
if($file = fopen($rawfile, "r")){
fclose($file);
} else {
echo "fail!";
}
另一个更新:感谢所有人的帮助,它确实是令人难以置信的愚蠢 - 权限问题。当较大的文件没有时,我的小文件莫名其妙地具有读权限。卫生署!
答案 0 :(得分:45)
你确定它是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 :(得分:7)
使用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()
更快。
答案 2 :(得分:1)
如果您只想输出文件,可以尝试使用readfile函数。
如果不是这种情况 - 也许您应该考虑应用程序的设计,为什么要在Web请求上打开如此大的文件?
答案 3 :(得分:1)
我使用fopen打开视频文件进行流式传输,使用php脚本作为视频流服务器,我对大小超过50/60 MB的文件没有任何问题。
答案 4 :(得分:1)
•在文本文件超过20 MB且解析速度大大降低之前,fgets()
功能还不错。
•file_ get_contents()
函数在40 MBytes之前给出了良好的结果,直到100 MBytes才得到可接受的结果,但是 file_get_contents()
将整个文件加载到内存中,因此它不是可扩展的。
•file()
函数对于大文本文件来说是灾难性的,因为此函数创建一个包含每一行文本的数组,因此该数组存储在内存中,并且使用的内存更大。
实际上,我只能用设置为2 GB的memory_limit
来解析200 MB的文件,这不适合我打算解析的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。
答案 5 :(得分:0)
如果问题是由达到内存限制引起的,您可以尝试将其设置为更高的值(这可能有效或无效,具体取决于php的配置)。
这将内存限制设置为12 Mb
ini\_set("memory_limit","12M");
答案 6 :(得分:0)
对我来说,fopen()
文件超过1mb的速度非常慢,file()
要快得多。
只是尝试一次读取100行并创建批量插入,fopen()
需要37秒,而file()
需要4秒。必须是string->array
file()
步骤
我会尝试所有文件处理选项,看看哪种方法最适合您的应用程序。
答案 7 :(得分:-1)