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

Мне было интересно, как изменить код ниже, чтобы прочитать x количество строк обрабатывает только инструкцию sql insert, а затем продолжает читать файл по номеру x и обрабатывать до конца файла. Я новичок в идее указателей файлов, но я понимаю, что это должно быть возможно с помощью 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 -> начнется с указателя -> повторить до тех пор, пока не будет.

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

Solutions Collecting From Web of "Работа с указателями файлов на csv"

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

Это немного переосмысление его колеса. mysql имеет очень быструю и эффективную систему для загрузки CSV-данных в таблицы. Это LOAD DATA INFILE, если у вас есть права на учетную запись пользователя, вы можете вызвать код справа внутри 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 eg.g.

 LOAD DATA INFILE ? IGNORE INTO TABLE ....