使用PHP将大文件分成许多较小的文件

Jar*_*red 1 php memory-management file pseudocode

我有一个209MB .txt文件,大约95,000行,每周一次自动推送到我的服务器,以更新我的网站上的一些内容.问题是我无法分配足够的内存来处理这么大的文件,因此我想将大文件分成较小的文件,每个文件有5,000行.

在文件被分成小块之前我根本不能使用file(),所以我一直在使用SplFileObject.但我无处可去.这是我想要实现的一些伪代码:

read the file contents

while there are still lines left to be read in the file
    create a new file
    write the next 5000 lines to this file
    close this file

for each file created
    run mysql update queries with the new content

delete all of the files that were created
Run Code Online (Sandbox Code Playgroud)

该文件采用csv格式.

编辑:以下是给出以下答案的逐行阅读文件的解决方案:

function getLine($number) {
    global $handle, $index;
    $offset = $index[$number];
    fseek($handle, $offset);
    return explode("|",fgets($handle));
}

$handle = @fopen("content.txt", "r");

while (false !== ($line = fgets($handle))) {
    $index[] = ftell($handle);
}

print_r(getLine(18437));

fclose($handle);
Run Code Online (Sandbox Code Playgroud)

Pho*_*nix 6

//MySQL Connection Stuff goes here

$handle = fopen('/path/to/bigfile.txt','r');  //open big file with fopen
$f = 1; //new file number

while(!feof($handle))
{
    $newfile = fopen('/path/to/newfile' . $f . '.txt','w'); //create new file to write to with file number
    for($i = 1; $i <= 5000; $i++) //for 5000 lines
    {
        $import = fgets($handle);
        fwrite($newfile,$import);
        if(feof($handle))
        {break;} //If file ends, break loop
    }
    fclose($newfile);
    //MySQL newfile insertion stuff goes here
    $f++; //Increment newfile number
}
fclose($handle);
Run Code Online (Sandbox Code Playgroud)

这应该工作,大文件应该通过每个文件5000行,输出文件,如newfile1.txt,newfile2.txt等,可以通过$i <= 5000for循环中的位调整.

哦,我明白了,你想要从大文件中插入数据,而不是存储有关文件的信息.然后只需使用fopen/fgets并插入直到feof.


Fer*_*yer 5

如果您的大文件是 CSV 格式,我猜您需要逐行处理它,实际上并不需要将其分解为较小的文件。不需要在内存中同时保存 5.000 行或更多行!为此,只需使用 PHP 的“低级”文件函数:

$fp = fopen("path/to/file", "r");

while (false !== ($line = fgets($fp))) {
    // Process $line, e.g split it into values since it is CSV.
    $values = explode(",", $line);

    // Do stuff: Run MySQL updates, ...
}

fclose($fp);
Run Code Online (Sandbox Code Playgroud)

如果您需要随机访问,例如逐行读取行号,您可以为您的文件创建一个“行索引”:

$fp = fopen("path/to/file", "r");

$index = array(0);

while (false !== ($line = fgets($fp))) {
    $index[] = ftell($fp);  // get the current byte offset
}
Run Code Online (Sandbox Code Playgroud)

现在$index将行号映射到字节偏移量,您可以使用以下命令导航到行fseek()

function get_line($number)
{
    global $fp, $index;
    $offset = $index[$number];
    fseek($fp, $offset);
    return fgets($fp);
}

$line10 = get_line(10);

// ... Once you are done:
fclose($fp);
Run Code Online (Sandbox Code Playgroud)

请注意,与文本编辑器不同,我从 0 开始行计数。