Работа с файловыми указателями на CSV

Мне было интересно, как изменить приведенный ниже код для чтения х число строк, только обработать оператор вставки 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.

  1. Является fgets() лучшее для этого?
  2. Нужно ли включить обратный вызов или что-то подобное, чтобы отложить обработку sql, пока все строки не будут прочитаны?
  3. Я немного растерялся, с чего начать, так как я все еще изучаю PHP.

**** Обновленный скрипт с ответом ниже, если он помогает кому-то еще …

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/>";

?>

2

Решение

  1. Является fgets() лучшее для этого? Это прекрасный способ сделать это. Другой вариант — прочитать весь файл в массив с file(), затем переберите массив с помощью foreach(),

  2. Нужно ли включить обратный вызов? Нет. Просто выполните запрос после прочтения каждой партии строк из файла.

  3. Когда начать? Когда счетчик достигнет размера пакета, выполните запрос. Затем установите счетчик обратно 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);
}
1

Другие решения

Это что-то вроде переосмысления колеса. 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 ....
1

По вопросам рекламы [email protected]