[RESOLU] modifier plusieurs fichiers csv d'un repertoire

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 12:03

Bonjour,
Je cherche a exécuter un script sur un ensemble de fichier de mon repertoire afin de supprimer la dernière colonne dans des fichiers csv.
<?php
	
foreach (glob("class_*") as $filename){


if (($handle_result = fopen($filename, "r+")) !== FALSE) 
{
if (($handle = fopen($filename, "r+")) !== FALSE) {
    while (($data = fgetcsv($handle, 100, ";")) !== FALSE) {
        
fputcsv($handle_result, array($data[0], $data[1], $data[2], $data[3], $data[4], $data[5], $data[6], $data[7]));
    }
    fclose($handle);
}
 fclose($handle_result);
}


}
?>
Ce sript produit une erreur
Request Timeout
Server timeout waiting for the HTTP request from the client.


J'arrive à exécuter les 2 parties du script de manière indépendante...
Je peux lister l'ensemble des fichiers répondant à mon critère :
foreach (glob("class_*") as $filename){
echo "<br> fichier : ".$filename;
}

d'un autre coté, si dans le code je remplace $filename par un nom de fichier, cela fonctionne bien.
if (($handle_result = fopen("class_toto.txt", "r+")) !== FALSE) 
{
if (($handle = fopen("class_toto.txt", "r+")) !== FALSE) {
    while (($data = fgetcsv($handle, 100, ";")) !== FALSE) {
        
fputcsv($handle_result, array($data[0], $data[1], $data[2], $data[3], $data[4], $data[5], $data[6], $data[7]));
    }
    fclose($handle);
}
 fclose($handle_result);
}
Je n'arrive pas a comprendre pourquoi la boucle sur les nom de fichiers ne permet pas de répéter le script, sachant que cette meme boucle sans la deuxième partie du script fonctionne bien...

Par avance merci pour vos lumières...

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 12:27

Salut, quand même surpris que tu puisses ouvrir 2 fois le même fichier en lecture écriture... le problème ne viendrait-il pas de la ?

EDIT : n'aurais tu pas créé une boucle infinie ? car tu lis une ligne puis en ajoutes une, puis en lis une, puis en ajoutes une, etc
Ça expliquerait un timeout.
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 12:47

Merci pour ton retour,
Pour la boucle, elle doit se faire tant que j'ai des fichiers du type class_.
si je demande seulement l'affichage du nom de fichier dans la boucle cela fonctionne..
donc sauf erreur de ma part, la boucle n'est pas infinie...

si je déconnecte les 2 scripts ils fonctionnent bien ...
C'est ce que je ne comprends pas...

Pour l'ouverture du fichier, si je remplace avec un nom de fichier, cela fonctionne correctement...

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 12:53

Bah sauf erreur de ma part si tu lis un fichier ligne à ligne avec un flux et qu'un deuxième flux vient ajouter une ligne à chaque ligne lu, je vois bien une boucle infinie, sauf si le fichier est vide au départ.

Me concernant, la logique serait de pousser les lignes modifiées dans un nouveau fichier et à la fin de la lecture, remplacer le fichier de lecture par le nouveau fichier. Et j'utiliserais les modes r et w.
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 12:57

Merci, je vais regarder cela

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 13:12

Bien vu @saian
Merci bcp

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 13:20

Cool ! voilà comment je l'aurais écris :
<?php

foreach (glob("class_*") as $filename)
{
  $fileRead = fopen($filename, 'r');
  $fileWrite = fopen($filename.'.tmp', 'w');

  if (!$fileRead || !$fileWrite) {
    echo "Erreur d'ouverture du fichier de lecture et/ou d'écriture avec $filename.";
    continue ;
  }

  while ($data = fgetcsv($fileRead))
  {
    unset($data[count($data) - 1]);
    fputcsv($fileWrite, $data);
  }

  fclose($fileWrite);
  fclose($fileRead);

  rename($filename.'.tmp', $filename);
}
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 15:18

Je viens de tester ta solution mais les fichiers retournés sont vides...
enfin il n'y a que des lignes vides...

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 15:24

voici avec quelques corrections... cela fonctionne :
$fileRead = fopen($filename, 'r');
  $fileWrite = fopen($filename.'.tmp', 'w');

  if (!$fileRead || !$fileWrite) {
    echo "Erreur d'ouverture du fichier de lecture et/ou d'écriture avec $filename.";
    continue ;
  }

  while ($data = fgetcsv($fileRead,100,";"))
  {
   // unset($data[count($data) - 1]);
    fputcsv($fileWrite, array($data[0], $data[1], $data[2], $data[3], $data[4], $data[5], $data[6], $data[7]),$delimiter=';');
  }

  fclose($fileWrite);
  fclose($fileRead);

  rename($filename.'.tmp', $filename);

Eléphanteau du PHP | 14 Messages

18 févr. 2020, 15:48

Petite question...
Sur certains enregistrement, j'ai des champs qui se retrouvent entre guillemet

par exemple
fichier initial :
085753;XXXX XXXX;aaaa;11/07/2008;C7564144;8;151;Homme;FRANCE

Fichier résultat :
085753;"XXXX XXXX";aaaa;11/07/2008;C7564144;8;151;Homme

le script a bien fonctionné en retirant la dernière colonne mais a ajouté des "" à XXXX XXXX

C'est le cas quand il y a un espace dans le champ en question...

Mammouth du PHP | 2703 Messages

18 févr. 2020, 15:53


Eléphanteau du PHP | 14 Messages

18 févr. 2020, 16:25

Oui j'avais bien lu cela...
mais je n'arrive pas a comprendre comment éviter l'encadrement automatique du champ par des " ".
j'ai essayé avec $enclosure='' pour spécifier un champ vide, mais cela ne fonctionne pas...
si je met $enclosure=' ' il me remplace bien les " " par des espaces..

Comment donc ne pas inclure les " " quand le champ comporte un espace ?

Avatar du membre
Mammouth du PHP | 1609 Messages

18 févr. 2020, 17:50

Si tu ne veux pas d'enclosure il faut que tu écrives la ligne avec fputs en joignant les éléments du tableau avec le delimiter et sans oublier le retour à la ligne en fin de ligne :
unset($data[count($data) - 1]);// retire le dernier élément du tableau
fputs($fileWrite, implode(';', $data)."\n");
Bien entendu tu auras des problèmes si une valeur contient le delimiter.

Ça donnerait quelque chose comme ça :
<?php 

$delimiter = ';';

foreach (glob("class_*") as $filename)
{
  $fileRead = fopen($filename, 'r');
  $fileWrite = fopen($filename.'.tmp', 'w');

  if (!$fileRead || !$fileWrite) {
    echo "Erreur d'ouverture du fichier de lecture et/ou d'écriture avec $filename.";
    continue ;
  }

  while ($data = fgetcsv($fileRead, 0, $delimiter))
  {
    unset($data[count($data) - 1]);
    fputs($fileWrite, implode($delimiter, $data)."\n");
  }

  fclose($fileWrite);
  fclose($fileRead);

  rename($filename.'.tmp', $filename);
}
Développeur web depuis + de 20 ans

Avatar du membre
Mammouth du PHP | 1609 Messages

19 févr. 2020, 12:33

PS : à la place du
unset($data[count($data) - 1]);
on pourrait avoir un
array_pop($data);
qui sert justement à dépiler le dernier élément du tableau.
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 14 Messages

19 févr. 2020, 15:05

Merci beaucoup pour l'aide ;-)