Aller au contenu

renvoyer les résultats au fur et à mesure (fopen)


Anonymus

Sujets conseillés

Lorsque j'ouvre un fichier distant avec fopen :

$fp  =fopen("file","r");
while(! feof($fp))
echo fgets($fp,4096);

Je m'apercois que le fichier est récupéré entièrement, puis seulement parcouru.

Ainsi, si je ne veux que la permière ligne de ce fichier, je suis bien obligé d'ouvrir le fichier dans son intégralité, puis seulement d'ouvrir cette première ligne.

C'est dommage, dans le cas de gros fichiers.

Existe-t-il une méthode, une fonction, qui ferait en sorte que le fichier ne soit pas récupéré entièrement, puis lu, mais récupéré ET lu, au fur et à mesure de sa récupération ?

Merci.

Lien vers le commentaire
Partager sur d’autres sites

Je suis assez étonné de ce que tu dis (mais je suppose que tu as du faire des essais) car j'ai toujours cru que le système d'exploitation lisait un groupe de clusters à la fois, groupe dont le nombre doit varier en fonction des optimisations au niveau de l'OS.

A l'époque du MS-DOS, ce nombre n'était pas très élevé, mais maintenant je suppose que cela doit englober un fichier de bonne taille (et en prime plein de caca inutile après la fin de fichier). Mais si le fichier dépasse une certaine taille, ce serait illogique qu'il lise tout (quoiqu'il faille sans doute compter avec les système de prédictions...)

En tout cas, il me semble que ce n'est pas du ressort de l'interpréteur php de gérer cela. Php ne nous offre d'ailleurs pas de fonctions bas niveau. Mais si tu as constaté cela sur des très gros fichiers, cela veut dire qu'il y a tout de même un problème.

EDIT: J'ai répondu à côté car je pensais qu'il parlait de la lecture physique bas niveau.

Modifié par Remi
Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

Peut-être en utilisant curl en définissant CURLOPT_RANGE pour récupérer une partie du fichier seulement. Le problème, c'est qu'il faut définir la longueur à lire, or on ne l'a connait qu'après avoir lu le fichier jusqu'au premier caractère de retour de ligne.

Il faudrait donc y aller à taton, en faisant plusieurs requêtes demandant une petite quantité de données:

$ch = curl_init("fichier.txt");
curl_setopt($ch,CURLOPT_RANGE, 0,4096); //Fais une requête et le serveur doit renvoyer les 4 premiers Ko
curl_exec($ch);
curl_close($ch);

(attention, je n'ai pas testé, j'ai juste lu un bout de la doc :whistling: )

Mais ça implique qu'il y ait plusieurs requêtes http (à moins que ce soit une connexion http persistante, mais là ça deviant franchement compliqué, je ne sais pas si curl sait faire les deux et si le serveur sera d'accord).

Lien vers le commentaire
Partager sur d’autres sites

pour un fichier de 10 lignes, le problème ne se pose pas.

Mais pour un fichier de quelques centaines d'octets, et qui n'est pas sur mon serveur, ca pose le problème de la page blanche pour l'internaute.

J'aurais voulu faire un système de présentation d'une partie du fichier (mettons les 10 premières lignes, et la suite vient après, ou quelque chose comme ca.

Mais là, je suis coincé. Je demande les 10 premières lignes, et il me renvoie de toute facon le fichier en entier...

Pour file, il enregistre le fichier dans un tableau, en premier, et après seulement il te le met à disposition :(

Il y a peut être un système de cache pour les fichiers, et une fonction telle que flush et ses dérivés :/

Pour CURL_RANGE, ca revient à lire le fichier avec fgets et 4096. Je n'ai pas essayé, mais c'est idem a priori..

Lien vers le commentaire
Partager sur d’autres sites

Je m'apercois que le fichier est récupéré entièrement, puis seulement parcouru.

<{POST_SNAPBACK}>

Tu parles de fichiers distants? tu utilises http je presume? Il ne me semble pas que http te permette de spécifier la taille de la réponse, ni si tu veux une partie de fichier. ce n'est pas un protocole pour gérer les échanges de fichiers.Si tu eux pouvoir télécharger juste une partie de fichier, il faut utiliser des protocoles adaptés comme le ftp.

Normalement pour les fichiers locaux, le fichier est parcouru au fur et à mesure et non pas lu en entier. (flux en local).

Lien vers le commentaire
Partager sur d’autres sites

J'utilises http, et c'est pour récupérer un xml. Mais de là à faire du ftp avec eux, c'est perdu d'avance :/

Lien vers le commentaire
Partager sur d’autres sites

Tu devrais essayer de mettre en place un système de cache de ton coté car je ne crois que le protocole http te permette de morceler tes fichiers... Ou sinon peux etre que tu peux negocier un format plus light du cote de ton fournisseur de fichier xml... En argumentant bien, il peut y voir un interet de proposer deux formats: 1 light "pour de la preview" et 1 complet. Enfin je dis cela mais je ne sais pas ce que tu veux echanger comme donnees ni avec qui tu les echanges...

Lien vers le commentaire
Partager sur d’autres sites

:D

Le système de cache est refusé par le client (dû au secteur d'activité), et le fournisseur (de xml) est assez... enfin.. c'est pas possible. :/

Lien vers le commentaire
Partager sur d’autres sites

ca va etre difficile de compresser l'incompressible. Je suis curieux de voir quelle solution tu proposeras à ton client... Tiens nous au courant. En parlant d'incompressible, est ce qu'au moins le xml passe par une connexion compressée?

Lien vers le commentaire
Partager sur d’autres sites

Bonsoir,

et du côté des Stream Functions (Fonctions de Flux) ?

Parce qu'après avoir lu quelques lignes de la RFC2616 - HTTP/1.1 et plus précisément la section 3.6, qui parle d'un transfert morcelé (Chunked Transfer).

The chunked encoding modifies the body of a message in order to transfer it as a series of chunks, each with its own size indicator, followed by an OPTIONAL trailer containing entity-header fields. This allows dynamically produced content to be transferred along with the information necessary for the recipient to verify that it has received the full message.

J'ai l'impression (je ne l'ai pas testé) que cela correspond à tes besoins...

stream_context_create (ou même fsockopen) devrait te permettre d'utiliser cette méthode...

Tout cela a condition que ton serveur Apache (ou autre) te permette de communiquer en HTTP/1.1 ... regarde dans les commentaires de du manuel PHP, il y a des exemples d'utilisation du Chunked Transfer...

Bonne chance et je serais ravis de voir ce à quoi tu es arrivé...ou au moins comment ;)

Lien vers le commentaire
Partager sur d’autres sites

Tu parles de fichiers distants? tu utilises http je presume? Il ne me semble pas que http te permette de spécifier la taille de la réponse, ni si tu veux une partie de fichier. ce n'est pas un protocole pour gérer les échanges de fichiers.Si tu eux pouvoir télécharger juste une partie de fichier, il faut utiliser des protocoles adaptés comme le ftp.

Normalement pour les fichiers locaux, le fichier est parcouru au fur et à mesure et non pas lu en entier. (flux en local).

<{POST_SNAPBACK}>

C'est justement là ou je voulais en venir :) lors de l'appel à fopen(), php est obligé de demander le fichiers au serveur, or il ne sait pas encore quelle partie du fichier va lui être utile et le protocole http l'oblige quand même à définir quelle partie du fichier récupérer, donc tant qu'à faire, il n'indique rien et le serveur lui envoie tout le fichier.

Pourtant, il y a un truc, sinon comment feraient les optimisateurs de téléchargement qui peuvent reprendre un téléchargement à partir d'un serveur http, lancer plusieurs connexions simultanées etc.

D'après la description du rfc concernant Chunked, je crois que c'est pas vraiment cette option, elle a l'air de se contenter d'envoyer le fichier en plusieurs morceaux coupées, mais ces morceaux sont encore une fois tous envoyés en même temps. Je crois que ça sert uniquement pour permettre aux navigateurs d'afficher progressivement les pages web qu'ils recoivent sans avoir à attendre la fin du transfert.

Par contre sur le site qu'à donner TheRec j'ai retrouvé l'histoire des "range":

http://www.w3.org/Protocols/rfc2616/rfc261...4.html#sec14.35

En clair, comme cette option est spécifiée avant l'envoi du fichier, le serveur sait quelle partie du fichier il faut qu'il envoie, et seule cette partie de fichier transite sur le net.

Il n'y a plus qu'à spécifier le header en question avec stream_context_create() ou alors utiliser la fonction de curl.

Lien vers le commentaire
Partager sur d’autres sites

Il y a un truc, mais... Php ne le fait pas forcément :/

J'aurais besoin d'ouvrir plusieurs fichiers en parallèle, et ca par exemple, Php ne le fait pas. Il faut attendre que l'un soit 'appelé', pour appeler le suivant.

Lien vers le commentaire
Partager sur d’autres sites

Il y a moyen de faire du multi-threading en PHP5 :

http://netevil.org/node.php?nid=280 (via http://www.atelierphp5.com/multi-threading-en-php.html)

Les fonctions de contrôle de processus servent aussi à cela, entre autres, à en croire le manuel...mais cela pose de problème de portabilité, la gestion de processus ne peut se faire que dans un environement Unix (à fortiori Linux)... Un explication d'un cas se trouve dans les commentaires du manuel ;)

Lien vers le commentaire
Partager sur d’autres sites

Comme tu fais un "while (! feof($fp))" tu vas effectivement lire tout le fichier tant que tu n'as pas atteint la fin de celui-ci.

Tu cherches explicitement le End-Of-File, non ? ;)

Dan

Lien vers le commentaire
Partager sur d’autres sites

En fait Anonymus a précisé rapidement dans son message d'origine qu'il veut accéder à des fichiers distants (et non locaux), il utilise donc les URL wrappers de PHP (fopen peut lire des fichiers distant grâce aux URL wrappers)...et par défaut ils ne permettent pas la récupération partielle de données pour les examiner... donc l'entier du fichier est téléchargé..

En utilisant les flux on peut utiliser les Ranges comme Boo2M0rs0 l'a dit...Quant à déterminer les Ranges (partie du fichier qu'on veut récupérer) c'est une autre histoire...

Les Chunks sont une autre alternative à mon avis, le fichier sera récupéré en entier en définitive...mais le fichier est morcelé (parts égales et déterminées tant que possible) et ces morceaux sont transférées les un après les autres...

Lien vers le commentaire
Partager sur d’autres sites

Comme tu fais un "while (! feof($fp))" tu vas effectivement lire tout le fichier tant que tu n'as pas atteint la fin de celui-ci.

Tu cherches explicitement le End-Of-File, non ? ;)

Dan

<{POST_SNAPBACK}>

Dans ce cas, oui. Mais c'etait juste un exemple.

Mon code est/etait plutot du genre (pour du xml) :

$stop=0;

on ouvre le fichier,

tant que blabla,

on lit

si $stop==10

on s'arrete

etc..

En fait, c'est surtout parce que je j'ai fini par mettre un compteur 'temps', qui me renvoie l'heure (la microseconde) d'execution du script, et que je vois que les 10 secondes d'ouverture de la page se passent pendant la ligne " fopen ".

Après, ca va vite, avant aussi.

C'est soit parce que le serveur en face est à la ramasse, soit parce qu'ils trainent lorsque c'est un gros fichier.

Dans certains cas, le fichier est tout petit. Là, ca ne prend pas plus d'une seconde. Mais dans la majorité des cas, ca dépasse les 4-5 secondes supportables. De quoi faire fuire l'internaute classique :/ (les autres aussi, d'ailleurs.. )

Les gros fichiers font 200-250 Ko. Il faut 10 secondes, pour en charger un ? (parce que là,. oui.)

Lien vers le commentaire
Partager sur d’autres sites

~200 KB en 10 secondes ? Après de multiples calculs savants (non je rigole) ça représente 20KB/s de moyenne... alors effectivement c'est peu si on parle de serveurs dédiés professionnels (avec une ligne décente)...toutefois c'est encore décent comme taux d'upload dans beaucoup de pays pour les connexions de particulier...

Mais à mon avis il est hors de question de se fier à ce type de débit pour récupérer des données essentielle à ta page ;)

Si c'est une question de l'ouverture du fichier en local (une fois transféré), c'est qu'il y a un problème sur le serveur qui ouvre ce fichier...j'ai eu ouvert de fichiers texte de plusieurs mégas en quelques millisecondes :)

Lien vers le commentaire
Partager sur d’autres sites

Veuillez vous connecter pour commenter

Vous pourrez laisser un commentaire après vous êtes connecté.



Connectez-vous maintenant
×
×
  • Créer...