Я начинающий разработчик, изучающий php. Задача, которую мне нужно сделать, — это загрузить CSV-файл объемом 6 ГБ, содержащий данные, в базу данных. Мне нужно получить доступ к данным, т.е. прочитать файл через файл controller.php и затем разбить его на части. этот огромный CSV-файл в 10000 строк выводит CSV-файлы и записывает данные в эти выходные CSV-файлы. Я выполнил это задание уже неделю и пока не разбираюсь. Не могли бы вы, ребята, помочь мне в решении этого вопроса.
<?php
namespace App\Http\Controllers;
use Illuminate\Queue\SerializesModels;
use App\User;
use DateTime;
use Illuminate\Http\Request;
use Storage;
use Validator;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Queue;
use App\model;
class Name extends Controller
{
public function Post(Request $request)
{
if($request->hasfile('upload')){
ini_set('auto_detect_line_endings', TRUE);
$main_input = $request->file('upload');
$main_output = 'output';
$filesize = 10000;
$input = fopen($main_input,'r');
$rowcount = 0;
$filecount = 1;
$output = '';
// echo "here1";
while(!feof($input)){
if(($rowcount % $filesize) == 0){
if($rowcount>0) {
fclose($output);
}
$output = fopen(storage_path(). "/tmp/".$main_output.$filecount++ . '.csv','w');
}
$data = fgetcsv($input);
print_r($data);
if($data) {
fputcsv($output, $data);
}
$rowcount++;
}
fclose($output);
}
}
}
Может быть, это потому, что вы создаете новый $output
обработчик файла для каждого iteration
,
Я внес некоторые коррективы, так что мы создаем файл только когда rowCount = 0 и закрываем его, когда fileSize
достигнуто Так же rowCount
должен быть сброшен в 0 каждый раз, когда мы закрываем файл.
public function Post(Request $request)
{
if($request->hasfile('upload')){
ini_set('auto_detect_line_endings', TRUE);
$main_input = $request->file('upload');
$main_output = 'output';
$filesize = 10000;
$input = fopen($main_input,'r');
$rowcount = 0;
$filecount = 1;
$output = '';
// echo "here1";
while(!feof($input)){
if ($rowCount == 0) {
$output = fopen('php://output', storage_path(). "/tmp/".$main_output.$filecount++ . '.csv','w');
}
if(($rowcount % $filesize) == 0){
if($rowcount>0) {
fclose($output);
$rowCount = 0;
continue;
}
}
$data = fgetcsv($input);
print_r($data);
if($data) {
fputcsv($output, $data);
}
$rowcount++;
}
fclose($output);
}
}
Вот рабочий пример разделения файла CSV по количеству строк (определяется как$numberOfLines
). Просто установите свой путь в $filePath
и запустите скрипт в оболочке, например:
php -f convert.php
код скрипта:
convert.php
<?php
$filePath = 'data.csv';
$numberOfLines = 10000;
$file = new SplFileObject($filePath);
//get header of the csv
$header = $file->fgets();
$outputBuffer = '';
$outputFileNamePrefix = 'datasplit-';
$readLinesCount = 1;
$readlLinesTotalCount = 1;
$suffix=0;
$outputBuffer .= $header;
while ($currentLine = $file->fgets()) {
$outputBuffer .= $currentLine;
$readLinesCount++;
$readlLinesTotalCount++;
if ($readLinesCount >= $numberOfLines) {
$outputFilename = $outputFileNamePrefix . $suffix . '.csv';
file_put_contents($outputFilename, $outputBuffer);
echo 'Wrote ' . $readLinesCount . ' lines to: ' . $outputFilename . PHP_EOL;
$outputBuffer = $header;
$readLinesCount = 0;
$suffix++;
}
}
//write remainings of output buffer if it is not empty
if ($outputBuffer !== $header) {
$outputFilename = $outputFileNamePrefix . $suffix . '.csv';
file_put_contents($outputFilename, $outputBuffer);
echo 'Wrote (last time)' . $readLinesCount . ' lines to: ' . $outputFilename . PHP_EOL;
$outputBuffer = '';
$readLinesCount = 0;
}
вы не сможете преобразовать такой объем данных за один запуск php, если он запускается из веб-формы, поскольку максимальное время выполнения сценариев php обычно составляет 30-60 секунд, и для этого есть причина — не пытайтесь выполнить событие расширить его до некоторого огромного числа. Если вы хотите, чтобы ваш скрипт работал даже в течение нескольких часов, вам нужно вызвать его из командной строки, но вы также можете вызвать его аналогичным образом из другого скрипта (например, у вашего контроллера)
Вы делаете это так:
exec('php -f convert.php');
и это все.
Контроллер, который у вас есть, не сможет определить, были ли преобразованы все данные, потому что до того, как это произойдет, они будут прерваны. Что вы можете сделать, это написать свой собственный код в convert.php
который обновляет какое-то поле в базе данных, а другой контроллер в вашем приложении может прочитать это и распечатать пользователю ход выполнения convert.php
,
Другой подход состоит в том, чтобы упорядочить работу / задания, которые вы можете поместить в очередь и которые могут выполняться процессом менеджера заданий с работниками, которые могут позаботиться о преобразовании, но я думаю, что это будет излишним для вашей потребности.
Имейте в виду, что если вы разделяете что-то и в другом месте присоединения у вас могут возникнуть проблемы с получением чего-то неправильного в этом процессе, метод, который обеспечит вам успешное разделение, передачу и объединение ваших данных, — это вычисление HASH, т.е. SHA-1 Целый файл 6 ГБ перед разделением, отправьте этот HASH в место назначения, где необходимо объединить все небольшие части данных, объедините их в один файл 6 ГБ, рассчитайте HASH этого файла и сравните с тем, который был отправлен. Имейте в виду, что каждая из небольших частей ваших данных после разделения имеет свой собственный заголовок, который будет CSV-файлом, который легко интерпретировать (импортировать), где в исходном файле у вас есть только одна строка заголовка.