Accès direct a un octet d'un fichier en php ?

WRInaute accro
Je travaille mon phprank again ...

Mon probleme du jour :

A ma droite (sur le serveur) un fichier catégorie mi-lourds (80k)

Et la je veux :

1 - recupérer l'octet d'offset nnnnn
2 - regarder sa valeur
3 - si ca me chante modifier la valeur de cet octet en position nnnnn

Methode brutale et consomatrice :
Je choppe tout le contenu, je change mon octet, je réecris tout le contenu

Methode "plus mieux bien":
Je choppe uniquement l'octet par file get content (avec pos et lg), je change mon octet et la je coince : comment je reecris que cet octet en position nnnnn en ecrasant l ancienne valeur ?

Question subsidiaire : est ce que le fait que mon fichier fasse 100k ou 10 mo a une incidence lorsque je fais un file get de 1 seul octet ? idem dans le sens "je réecris un octet" ...
 
WRInaute accro
fopen, fseek, fread, fseek, fwrite, fclose.

Avec cette méthode c'est très "light" quelle que soit la taille du fichier.

Jacques.
 
WRInaute accro
Bon c'est testé et validé ... Ca marche impec. Merci jacques.

Par contre a propos de l'impact de la taille du fichier ... je voudrais être sûr parce que de cela dépendent des choix structurels ...

Pour bien me faire comprendre :

- Je veux gérer une sorte de "map" qui va suivre l'état (ON=1 OFF=0) d'environ 10 millions de références identifiées par un id qui vas de 0 à 9.999.999.
- Actuellement, craignant que la taile du fichier impacte sur la vitesse de travail (cf ci dessus open seek read etc ...), j'ai généré 1000 fichiers .txt de 10000 octets chacun remplis de "0" et lorsque je dois passer un octet à "1" je choisis d'abord le bon fichier et je vais mettre a jour mon octet.

Si la taille n'a vraiment aucun impact, je serait alors plus tenté de travailler juste avec 10 fichiers.txt de 1 millions de caractères ...

Ton avis maintenant que tu connais le contexte (je ne fais aucune autre opération que ce qui est decrit plus haut sur ces fichiers).

Cerise on ze cake (la je sens que j'abuse mais bon ...) :

Puisque mes flags se limitent à 0 ou 1 ... c'est con de perdre un octet pour ca (surtout multiplié par 10 millions ... qui peuvent evoluer vers 2 3 ou 10 fois plus !). Alors je me demandais si en php on avait comme dans d'autres langages la possibilité de modifier individuellement chacun des 8 bits ... parce que en fait avec 0 et 1 je pourrais stocker 8 flags sur un octet et pas 1 seul ... J'exagère ou c'est envisageable en php ?
 
WRInaute accro
J'allais commencer par ça... Si tu n'as que deux états, un bit par référence suffit.

offset = reference / 8
bit = reference % 8
mask = 1 << bit

Mettre à 0: octet &= ~mask
Mettre à 1: octet |= mask
Tester: octet & mask

NB: c'est garanti jusqu'à environ 2 milliards de références. Au delà tu risques d'atteindre les limites sur les entiers 32 bits et il va falloir faire un peu attention pour ne pas avoir de problème.

Et je confirme, que ton fichier fasse 1 octet ou 1 Go, si tu ne lis/écris qu'un seul octet à la fois, aucune différence.

Jacques.
 
WRInaute accro
jacques je t'adooooore ! :mrgreen:

Bon normalement pas de pb de limite ... le maxi se situe aux environ des 250 millions.
 
WRInaute passionné
euh... si vous voulez on peut partir sans faire de bruit.

On vous allumera les bougies :mrgreen:
 
WRInaute accro
jcaron a dit:
J'allais commencer par ça... Si tu n'as que deux états, un bit par référence suffit.

offset = reference / 8
bit = reference % 8
mask = 1 << bit

Mettre à 0: octet &= ~mask
Mettre à 1: octet |= mask
Tester: octet & mask

NB: c'est garanti jusqu'à environ 2 milliards de références. Au delà tu risques d'atteindre les limites sur les entiers 32 bits et il va falloir faire un peu attention pour ne pas avoir de problème.

Et je confirme, que ton fichier fasse 1 octet ou 1 Go, si tu ne lis/écris qu'un seul octet à la fois, aucune différence.

Jacques.
Bon à la lumière de tout ca j'ai opté pour un fichier de 3.000.000 d'octets (soit 24.000.000 de references couvertes. Si besoin de plus je ferais un second fichier (3mo c'est pour le coté plus pratique a manipuler sur ftp qu'un bouzin de 1Go).

Par contre comme je decouvre ces syntaxes sur les bits, je suis un peu perdu sur la syntaxe exacte.

en entrée j'ai un $id qui contient ma reference (disons 1.432.624) et $chemin le chemin vers mon doc, mais ensuite je patauge pour faire ca :

Code:
$fp=fopen ($chemin, 'r+');
$offset=intval($id/8)
fseek ($fp, $offset);
$octet=fread ($fp, 1)
$valeurbit= ?????????

if ($valeurbit == 0)
  {
      ??????? changer valeur bit dans $octet
     fseek ($fp, $offset);
     fwrite ($fp, $octet, 1);
  }

fclose ($fp)

Il me manque quelques briques :roll:
 
WRInaute accro
Ben alors, on a oublié d'ouvrir les yeux à la fin de la sieste?

$mask = 1 << ($id % 8);
test: if ($octet & $mask) ou if (!($octet & $mask)) suivant les cas

(note que le résultat vaut "autre chose que 0" si le bit est à 1, mais pas forcément 1)

mettre le bit à 0: $octet &= ~$mask;
mettre le bit à 1: $octet |= $mask;

C'était tout dans le message précédent (à part les $).

Jacques.
 
WRInaute impliqué
Ce sujet me passionne depuis le début, vraiment bravo pour cette astuce :)


(100eme poste wri en passant :mrgreen: )
 
WRInaute accro
Voila qui met un joli point d'orgue a ce topic :

debut : 0.70166300 1273264774
fin : 0.71765500 1273264774
durée : 0.015992

ca couvre tout :

open
read
seek
test 0 ou 1
seek
maj en 1
fwrite
fclose

Sur un fichier de 5.000.000 d'octets (oui oui je sais j'avais dit 3.000.000 et puis vous savez ce que c'est la gourmandise :mrgreen: ) (sur du mutu chez netavous)

Jacques ... si tu passes à Marrakech (!) , rappelle moi que je te dois une mousse :mrgreen:

Edit : comme c'est sur un mutu, ca fluctue (dans le bon sens ici) :

========= maj map ========
debut : 0.78282900 1273265849
fin : 0.78986500 1273265849
durée : 0.007036

bref durée marginale effectivement.
 
Discussions similaires
Haut