Intereting Posts
Используйте .htaccess, чтобы предотвратить доступ к корневому каталогу из открытого доступа Пользовательский запрос SugarCRM в всплывающем списке Возможно ли PhpStorm автоматически заполнять поле БД в виде строки в файле PHP? PHP – редактирование / удаление определенной строки в файле предупреждение: ожидает, что параметр 1 будет mysqli_result Как заставить phpexcel вести ведущие 0 в телефонных номерах? Санизировать предложение в php свойство динамического класса $$ значение в php Алгоритм для получения всех возможных комбинаций строк из массива до определенной длины Как получить доступ к этому значению объекта? ContextErrorException после создания пакета в Symfony file_get_contents не удалось открыть поток: HTTP-запрос не удался! Внутренняя ошибка сервера HTTP / 1.1 500 Является ли ini_set ('max_execution_time', 0) плохой идеей? unlink не может удалить файл mysql вставить в таблицу его имя содержит тире

Перерыв большого файла во множество небольших файлов с PHP

У меня есть 209 МБ. TXT-файл, содержащий около 95 000 строк, которые автоматически переносятся на мой сервер один раз в неделю для обновления содержимого на моем сайте. Проблема в том, что я не могу выделить достаточно памяти для обработки такого большого файла, поэтому я хочу разбить большой файл на более мелкие файлы по 5000 строк каждый.

Я не могу использовать файл () вообще, пока файл не разбит на более мелкие части, поэтому я работал с 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 

Файл находится в формате csv.

EDIT: Вот решение для чтения файла по строке, приведенного ниже:

 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); 

    Если ваш большой файл находится в формате CSV, я предполагаю, что вам нужно обрабатывать его по строкам и на самом деле не нужно разбивать его на более мелкие файлы. Не должно быть необходимости держать 5000 или более строк в памяти сразу! Для этого просто используйте «низкоуровневые» функции PHP:

     $fp = fopen("path/to/file", "r"); while (false !== ($line = fgets($fp))) { // Process $line, eg split it into values since it is CSV. $values = explode(",", $line); // Do stuff: Run MySQL updates, ... } fclose($fp); 

    Если вам нужен произвольный доступ, например, прочитайте строку за строкой, вы можете создать «индекс строки» для вашего файла:

     $fp = fopen("path/to/file", "r"); $index = array(0); while (false !== ($line = fgets($fp))) { $index[] = ftell($fp); // get the current byte offset } 

    Теперь $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); 

    Обратите внимание, что я начал подсчет строк в 0, в отличие от текстовых редакторов.

     //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); в //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); 

    Это должно работать, большой файл должен проходить через 5000 строк на файл, а выходные файлы, такие как newfile1.txt, newfile2.txt и т. Д., Могут быть скорректированы с помощью бита $i <= 5000 в цикле for.

    О, я вижу, вы хотите сделать вложение данных из большого файла, а не хранить информацию о файлах. Затем просто используйте fopen / fgets и вставьте до feof.

    Вы можете использовать fgets для чтения по строкам.

    Вам нужно будет создать функцию, чтобы поместить прочитанное содержимое в новый файл. Пример:

     function load(startLine) { read the original file from a point startline puts the content into new file } 

    После этого вы можете вызывать эту функцию рекурсивно, чтобы передать startline функции в каждом цикле чтения.

    Это должно сделать трюк для вас, у меня нет очень большого текстового файла, но я протестировал его с файлом длиной 1300 строк и разделил файл на 3 файла:

      // Store the line no: $i = 0; // Store the output file no: $file_count = 1; // Create a handle for the input file: $input_handle = fopen('test.txt', "r") or die("Can't open output file."); // Create an output file: $output_handle = fopen('test-'.$file_count.'.txt', "w") or die("Can't open output file."); // Loop through the file until you get to the end: while (!feof($input_handle)) { // Read from the file: $buffer = fgets($input_handle); // Write the read data from the input file to the output file: fwrite($output_handle, $buffer); // Increment the line no: $i++; // If on the 5000th line: if ($i==5000) { // Reset the line no: $i=0; // Close the output file: fclose($output_handle); // Increment the output file count: $file_count++; // Create the next output file: $output_handle = fopen('test-'.$file_count.'.txt', "w") or die("Can't open output file."); } } // Close the input file: fclose($input_handle); // Close the output file: fclose($output_handle); 

    Проблема, которую вы теперь можете найти, – это время выполнения слишком велико для скрипта, когда вы говорите о 200 + mb-файле.

    Если это выполняется на сервере linux, просто попробуйте php, чтобы в командной строке выполнялось следующее:

    split -l 5000 -a 4 test.txt out

    Затем залейте результаты для имен файлов, которые вы можете открыть.


    Я думаю, что ваш алгоритм неудобен, похоже, что вы разрываете файлы без причины. Если вы просто открываете исходный файл данных и читаете его по очереди, вы все равно можете выполнить форматирование mysql, а затем просто удалите файл.