Мне было интересно, как изменить приведенный ниже код для чтения х число строк, только обработать оператор вставки sql затем продолжить чтение файла по х число и обрабатывать до конца файла. Я новичок в идее файловых указателей, но я понимаю, что это должно быть возможно с помощью fgets.
Я надеюсь изменить приведенный ниже код на функцию, в которой я могу передать имя файла и количество строк, которые я хочу прочитать и обработать.
В настоящее время у меня есть:
(от Вот)
$handle = fopen(dirname(__FILE__)."/files/workorderstest.csv" , "r");
$batch++;
if ($handle) {
$counter = 0;
//instead of executing query one by one,
//let us prepare 1 SQL query that will insert all values from the batch
$sql ="INSERT INTO workorderstest(id,parentid,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES ";
while (($line = fgets($handle)) !== false) {
$sql .= "($line),";
$counter++;
}
$sql = substr($sql, 0, strlen($sql) - 1);
var_dump($sql);
if ($conn->query($sql) === TRUE) {
} else {
}
fclose($handle);
}
Я хочу свести к минимуму объем памяти. Я думаю, что это просто вопрос отслеживания указателя -> повторять, пока не достигнуты строки -> обработать sql -> начать с указателя -> повторять до eof.
fgets()
лучшее для этого?**** Обновленный скрипт с ответом ниже, если он помогает кому-то еще …
date_default_timezone_set('Australia/Brisbane');
$date = date('m/d/Y h:i:s a', time());
$timezone = date_default_timezone_get();
$time_start = microtime(true);
$batch_size = 500; // Lines to be read per batch
$batch = 0;
$counter = 0;
$lines = 0;
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Remove Existing Data from table
$sql = "TRUNCATE TABLE `workorderstest`";
$conn->query($sql);
$handle = fopen(dirname(__FILE__)."/files/workorders.csv" , "r");
//instead of executing query one by one,
//let us prepare 1 SQL query that will insert all values from the batch
$sql_prefix ="INSERT INTO workorderstest(id,parentid,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES ";
$values = "";
while (($line = fgets($handle)) !== false) {
$values .= "($line),";
$counter++;
$lines++;
if ($counter == $batch_size) {
$values = substr($values, 0, strlen($values) - 1);
$conn->query($sql_prefix . $values) or die($conn->error);
$counter = 0;
$values ="";
$batch++;
}
}
if ($counter > 0) { // Execute the last batch
$values = substr($values, 0, strlen($values) - 1);
$conn->query($sql_prefix . $values) or die($conn->error);
}
// Output results
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "Importing Script running at: $date <br/>";
echo "Timezone: $timezone <br/>";
echo "<br/>";
echo "Script Summary:";
echo "Time running script: " . round($time,3) . " seconds <br/>";
echo "Memory: ".memory_get_usage() . " bytes <br/>";
echo "Records Updated: $lines <br/>";
echo "Batches run: $batch <br/>";
?>
Является fgets()
лучшее для этого? Это прекрасный способ сделать это. Другой вариант — прочитать весь файл в массив с file()
, затем переберите массив с помощью foreach()
,
Нужно ли включить обратный вызов? Нет. Просто выполните запрос после прочтения каждой партии строк из файла.
Когда начать? Когда счетчик достигнет размера пакета, выполните запрос. Затем установите счетчик обратно 0
и установите строку запроса обратно в начальное значение. Наконец, в конце цикла вам нужно выполнить запрос с оставшимися значениями (если только размер файла не был точно кратным размеру пакета, в этом случае ничего не останется).
$batch_size = 100;
$counter = 0;
//instead of executing query one by one,
//let us prepare 1 SQL query that will insert all values from the batch
$sql_prefix ="INSERT INTO workorderstest(id,parentid,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES ";
$values = "";
while (($line = fgets($handle)) !== false) {
$values .= "($line),";
$counter++;
if ($counter == $batch_size) {
$values = substr($values, 0, strlen($values) - 1);
$conn->query($sql_prefix . $values) or die($conn->error);
$counter = 0;
$values ="";
}
}
if ($counter > 0) { // Execute the last batch
$values = substr($values, 0, strlen($values) - 1);
$conn->query($sql_prefix . $values) or die($conn->error);
}
Это что-то вроде переосмысления колеса. MySQL имеет очень быструю и эффективную систему для загрузки данных CSV в таблицы. Это НАГРУЗКА ДАННЫХ ИНФИЛЬ если у вас есть необходимые разрешения для вашей учетной записи, вы можете вызвать код прямо из PHP. И LOAD DATA имеет встроенную поддержку пропуска N строк.
$path = dirname(__FILE__)."/files/workorderstest.csv";
$q = "LOAD DATA INFILE ? INTO TABLE workorderstest IGNORE ? LINES";
$stmt = $dbh->prepare($q);
$stmt->bindParam(1,"$dirname");
$stmt->bindParam(2,"$n");
$stmt->execute();
Это драгоценные строки кода не так ли?
Обратите внимание, что этот код использует ключевые слова IGNORE LINES для пропуска строк в CSV. Вы также можете использовать ключевое слово IGNORE, например.
LOAD DATA INFILE ? IGNORE INTO TABLE ....