Trabalhando com pointers de arquivo em um csv

Eu queria saber como mudar o código abaixo para ler x número de linhas apenas processar a instrução sql insert, em seguida, continuar a ler o arquivo por número x e processar até o final do arquivo. Eu sou novo na idéia de pointers de arquivos, mas eu entendo que deveria ser possível usando fgets.

Estou esperando mudar o código abaixo para uma function onde eu posso passar o nome do arquivo e o número de linhas que eu quero ler e processar.

Eu atualmente tenho: (a partir daqui )

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

Quero manter a pegada da memory no mínimo. Estou pensando que isso deve ser apenas uma questão de manter o controle do ponteiro -> repetir até as linhas alcançadas -> processo sql -> começar no ponteiro -> repetir até eof.

  1. O fgets() o melhor para usar para isso?
  2. Preciso incorporar um retorno de chamada ou algum tal para adiar o processamento sql até que todas as linhas sejam lidas?
  3. Estou um pouco perdido, por onde começar porque ainda estou aprendendo PHP.

**** Atualizado o script respondido abaixo se ajudar alguém …

 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 
"; echo "Timezone: $timezone
"; echo "
"; echo "Script Summary:"; echo "Time running script: " . round($time,3) . " seconds
"; echo "Memory: ".memory_get_usage() . " bytes
"; echo "Records Updated: $lines
"; echo "Batches run: $batch
"; ?>

  1. O fgets() o melhor para usar para isso? É uma boa maneira de fazê-lo. Outra opção é ler o arquivo inteiro em uma matriz com o file() , então aperte a matriz com foreach() .

  2. Preciso incorporar um retorno de chamada? Não. Apenas execute a consulta depois de ler cada lote de linhas do arquivo.

  3. Onde começar? Quando o contador atinge o tamanho do lote, execute a consulta. Em seguida, ajuste o contador de volta para 0 e defina a seqüência de consulta de volta para o valor inicial. Finalmente, no final do loop, você precisará executar a consulta com os valores restantes (a menos que o tamanho do arquivo seja um múltiplo exato do tamanho do lote, caso em que não haverá nada restante).

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

Este é um pouco de reinvenção da roda. mysql possui um sistema muito rápido e eficiente para carregar dados CSV em tabelas. Isso é LOAD DATA INFILE se você tem as permissions corretas em sua conta de usuário, você pode invocar o código diretamente do PHP. E LOAD DATA construiu suporte para ignorar N linhas.

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

São algumas poucas linhas de código, não é?

Observe que este código usa as palavras-chave IGNORE LINES para ignorar linhas no CSV. Você também pode usar a palavra-chave IGNORE eg.g

 LOAD DATA INFILE ? IGNORE INTO TABLE ....