OVH Cloud OVH Cloud

Ecrire et sauvegarder en binaire

10 réponses
Avatar
Pascal
Bonjour,

Pour les besoins de mon projet, j'aurais besoin de sauvegarder dans une
structure du binaire (de l'ordre de 512 octets). Pour cela, ce forum m'a
conseillé d'utiliser le bitset.

Maintenant, il faut que je puisse sauvegarder ce contenu dans un fichier
à accès séquentiel. Et là je bloque. Comment faire?
--
Pascal

10 réponses

Avatar
Fabien LE LEZ
On Fri, 11 Feb 2005 18:34:23 +0100, Pascal :

Maintenant, il faut que je puisse sauvegarder ce contenu dans un fichier
à accès séquentiel. Et là je bloque. Comment faire?


Commencer par définir un format de fichier, si possible facilement
extensible (au cas où tu veuilles ajouter d'autres types
d'informations par la suite).
Ensuite, programmer les fonctions de lecture et d'écriture -- ce qui
devrait être assez simple si les spécifications du format sont bien
claires.

Je te propose un format très simple et qui remplit bien son office
pour des données de petite taille : une ligne par information, au
format nom=valeur

Ici, "nom" est vraisemblablement qui ressemble au nom de la variable
de type bitset ; "valeur" est le contenu de tes bits, soit un par un
(i.e. une suite de '1' et de '0'), soit quatre par quatre (en
hexadécimal).


--
;-)

Avatar
Ivan Vecerina
Bonjour,
"Pascal" wrote in message
news:420cecdd$0$628$
Pour les besoins de mon projet, j'aurais besoin de sauvegarder dans une
structure du binaire (de l'ordre de 512 octets). Pour cela, ce forum m'a
conseillé d'utiliser le bitset.
Sauvegarder quelle genre de données binaires?

Pourquoi bitset s'est-il imposé?

Si tu utilises bitset, le plus simple serait probablement
d'appeler la fonction membre to_string() et d'en écrire
le résultat directement, sous forme textuelle ("100110...").
Ceci à moins qu'un format plus compact ne soit requis.

Maintenant, il faut que je puisse sauvegarder ce contenu dans un fichier à
accès séquentiel. Et là je bloque. Comment faire?
Tu devrais donner une description plus globale des besoins de ton

projet, ou du moins de l'ensemble des opérations qui seront à effectuer
sur cette structure binaire. Pour pouvoir proposer la meilleure
solution, il faut une vue d'ensemble du problème.


Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form

Avatar
Pierre Maurette
Bonjour,

Pour les besoins de mon projet, j'aurais besoin de sauvegarder dans une
structure du binaire (de l'ordre de 512 octets). Pour cela, ce forum m'a
conseillé d'utiliser le bitset.

Maintenant, il faut que je puisse sauvegarder ce contenu dans un fichier
à accès séquentiel. Et là je bloque. Comment faire?
Votre problème est un peu flou, en particulier sur le sens exact de

"binaire". Si vos 512 octets représentent réellement 4096 valeurs
binaires, et si vous voulez accéder séquentiellement *au niveau du bit*,
le bitset va vous embêter plus qu'autre chose.
Si vous n'êtes pas ras duc en mémoire, vous pourriez tout simplement
représenter ces valeurs "binaire" par des scalaires:

typedef enum {zero, un} binaire;
ou
typedef int binaire;
ou
typedef char binaire;

binaire tampon[4096];
ou
binaire* pTampon = malloc(tailleTampon * sizeof(binaire));

(ou toute autre façon de gérer un tableau statique ou dynamique plus "C++").

Vous "perdez" de la place dans un rapport de 1 à 8 et jusqu'à 1 à 32
selon l'implémentation, mais manipulation, sauvegarde et lecture
deviennent triviales.
--
Pierre

Avatar
Pascal
Pascal wrote:
Bonjour,

Pour les besoins de mon projet, j'aurais besoin de sauvegarder dans une
structure du binaire (de l'ordre de 512 octets). Pour cela, ce forum m'a
conseillé d'utiliser le bitset.

Maintenant, il faut que je puisse sauvegarder ce contenu dans un fichier
à accès séquentiel. Et là je bloque. Comment faire?


Bon apparament ça manque de précision. Mais c'est assez complexe. C'est
un projet de SGBD. Le fichier binaire contient la base. Ce fichier peut
donc théoriquement avoir une taille gigantesque (plusieurs giga). Il me
faut donc un accès séquentiel pour modif une donnée. Parce que si pour
modifier 2 bits, je dois recopier le fichier, je risque d'avoir une très
mauvaise note...

Le format du fichier? C'est celui d'une base SGBD. Le fichier est
séparée en plusieurs "page". Une page aura une taille standard de 512
octets (en général elle est de 4ko dans un vrai SGBD, mais reste
paramètrable). Il me faut donc dans un premier temps pouvoir me déplacer
de page en page dans ce fichier.
Une page sert à stocker les nuplets de la relation. A la fin de chaque
page, il y a un gestionnaire de nuplets. Il permet de savoir le nombre
de nuplets qu'il y a sur la page (le dernier octet de la page), et
surtout de savoir les emplacement libre grâce à des bits signé sur 2
octets (+20 correspond à un emplacement libre de 20bits, -10 correspond
à un emplacement occupé par un nuplet de taille 10bits).
La première "page" de la base est une page d'état qui permet de savoir
si une page est libre ou occupée (une page libre ne contient aucun
nuplets). Elle associe un bit au numéro de la page. Exemple : si le
deuxième bit est à 0, cela veut dire que la deuxième page est libre. Si
la page fait 512 octets, cela fait donc 512* adresses de pages.

Donc pour mon projet, j'ai besoin de pouvoir stocker sous forme binaire
mes données, et aussi pouvoir stocker en mémoire vive le contenu d'une
page, d'où le bitset non?

--
Pascal

Avatar
Ivan Vecerina
"Pascal" wrote in message
news:420dc551$0$8221$
Pascal wrote:
Bonjour,

Pour les besoins de mon projet, j'aurais besoin de sauvegarder dans une
structure du binaire (de l'ordre de 512 octets). Pour cela, ce forum m'a
conseillé d'utiliser le bitset.

Maintenant, il faut que je puisse sauvegarder ce contenu dans un fichier
à accès séquentiel. Et là je bloque. Comment faire?


Bon apparament ça manque de précision. Mais c'est assez complexe. C'est un
projet de SGBD. Le fichier binaire contient la base. Ce fichier peut donc
théoriquement avoir une taille gigantesque (plusieurs giga). Il me faut
donc un accès séquentiel pour modif une donnée. Parce que si pour modifier
2 bits, je dois recopier le fichier, je risque d'avoir une très mauvaise
note...
...

Donc pour mon projet, j'ai besoin de pouvoir stocker sous forme binaire
mes données, et aussi pouvoir stocker en mémoire vive le contenu d'une
page, d'où le bitset non?


Non, probablement pas.

Un tableau de unsigned char (ou vector<unsigned char>) est la manière
typique de traiter des données brutes (binaires) en C++.
Pour les entrées/sorties, les fonctions de la librairie héritée du C
( fopen, fwrite, etc ) sont probablement celle qu'il faudrait utiliser.

Pour un projet académique en C++, je ne pense pas qu'il faille aller
chercher plus loin (memory-mapping et caches, mots 32 ou 64 bits, ...).

Sur la base d'un tableau d'unsigned char (8-bit), toutes les
extractions/modifications/écritures de champs de taille quelquonque
peuvent être implémentées au besoin.


Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form


Avatar
Pierre Maurette
[...]
Sur la base d'un tableau d'unsigned char (8-bit), toutes les
extractions/modifications/écritures de champs de taille quelquonque
peuvent être implémentées au besoin.
Une bonne pratique serait peut-être de remplacer l'unsigned char par un

uint8_t. Bon, la plupart du temps le préprocesseur fera le chemin
inverse, mais si le compilateur ne propose pas ce type, ce sera
peut-être signe que le unsigned char ne fait pas exactement 8 bits sans
padding et évitera de compiler n'importe quoi.
--
Pierre

Avatar
Pascal
On Sat, 12 Feb 2005 13:21:26 +0100, Ivan Vecerina wrote:

Un tableau de unsigned char (ou vector<unsigned char>) est la manière
typique de traiter des données brutes (binaires) en C++.
Pour les entrées/sorties, les fonctions de la librairie héritée du C
( fopen, fwrite, etc ) sont probablement celle qu'il faudrait utiliser.



Est ce que les fonctions write et read de la classe ofstream sont
correctes?
On m'a dit qu'on ne pouvait pas écrire bit à bit dans un fichier. Qu'il
fallait travailler octet par octet (et donc faire des mask pour travailler
bit à bit). Est ce bien vrai? De plus, j'ai trouvé une page qui parle
d'écriture en binaire :
http://forum.hardware.fr/hardwarefr/Programmation/Ecriture-Lecture-de-fichier-binaire-ios-binary-avec-et--sujet-57868-1.htm

Et donc toutes les fonctions que je me suis fatigué à faire depuis 1heure
sont déjà implémenté...

Avatar
Ivan Vecerina
"Pascal" wrote in message
news:
On Sat, 12 Feb 2005 13:21:26 +0100, Ivan Vecerina wrote:
Un tableau de unsigned char (ou vector<unsigned char>) est la manière
typique de traiter des données brutes (binaires) en C++.
Pour les entrées/sorties, les fonctions de la librairie héritée du C
( fopen, fwrite, etc ) sont probablement celle qu'il faudrait utiliser.


Est ce que les fonctions write et read de la classe ofstream sont
correctes?
[NB: c'est fstream (sans 'o') pour faire write *et read*]

Oui, si utilisées correctement (pas tj évident). Pour des entrées/sorties
purement binaire, on a en fait seulement besoin de l'objet filebuf
contenu dans i/o/-fstream.
Pour des e/s purement binaire, il est parfois plus simple et efficace
d'utiliser la librairie du C - c'est pourquoi je l'ai mentionée.

On m'a dit qu'on ne pouvait pas écrire bit à bit dans un fichier. Qu'il
fallait travailler octet par octet (et donc faire des mask pour travailler
bit à bit). Est ce bien vrai?


Oui, il est vrai que les fonctions d'entrées/sortie de la librairie
C ou C++ travaillent toujours sur un nombre entier d'octets (dont la
représentation la plus proche, en C et C++, est unsigned char -- et dont
il est bien sûr judicieux de faire un typedef).
Au niveau du disque dur, les e/s se font en fait même par page ou
secteur, du genre 4k à la fois. Donc si tu écris 1 octet, le système
va typiquement lire le secteur original, y modifier l'octet, puis
écrire le secteur modifié. (Pareil pour 512 octets). C'est pourquoi
les applications optimisées vont utiliser des pages de données qui
correspondent à la taille des secteurs disque (typiquement 4k).

C'est pourquoi il est très raisonnable de lire ou écrire toute une page
à la fois, et de faire le reste directement en mémoire.

De plus, j'ai trouvé une page qui parle
d'écriture en binaire :
http://forum.hardware.fr/hardwarefr/Programmation/Ecriture-Lecture-de-fichier-binaire-ios-binary-avec-et--sujet-57868-1.htm

Et donc toutes les fonctions que je me suis fatigué à faire depuis 1heure
sont déjà implémenté...
Pour autant que tous tes champs soient constitués par un nombre

entier d'octets (1, 2 ou 4), oui. Il faut aussi prendre en compte
les questions de portabilité (p.ex. little- ou big-endian) - et
là la solution proposée dans ce lien n'offre aucune garantie.



--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form


Avatar
James Kanze
Ivan Vecerina wrote:
"Pascal" wrote in message
news:420dc551$0$8221$


Pascal wrote:



Pour les besoins de mon projet, j'aurais besoin de
sauvegarder dans une structure du binaire (de l'ordre de 512
octets). Pour cela, ce forum m'a conseillé d'utiliser le
bitset.




Maintenant, il faut que je puisse sauvegarder ce contenu dans
un fichier à accès séquentiel. Et là je bloque. Comment
faire?




Bon apparament ça manque de précision. Mais c'est assez
complexe. C'est un projet de SGBD. Le fichier binaire contient
la base. Ce fichier peut donc théoriquement avoir une taille
gigantesque (plusieurs giga). Il me faut donc un accès
séquentiel pour modif une donnée. Parce que si pour modifier 2
bits, je dois recopier le fichier, je risque d'avoir une très
mauvaise note...



...


Donc pour mon projet, j'ai besoin de pouvoir stocker sous
forme binaire mes données, et aussi pouvoir stocker en mémoire
vive le contenu d'une page, d'où le bitset non?



Non, probablement pas.


Un tableau de unsigned char (ou vector<unsigned char>) est la
manière typique de traiter des données brutes (binaires) en
C++. Pour les entrées/sorties, les fonctions de la librairie
héritée du C ( fopen, fwrite, etc ) sont probablement celle
qu'il faudrait utiliser.


Ça dépend. En théorie, filebuf doit marcher très bien, à
condition de ne pas oublier de l'imbuer avec une locale "C".
Dans la pratique, je me servirais prèsque certainement d'une
interface plus bas : open, read, write, etc. sous Unix, par
exemple. Mais si le devois est de l'écrire en C++...

Pour un projet académique en C++, je ne pense pas qu'il faille
aller chercher plus loin (memory-mapping et caches, mots 32 ou
64 bits, ...).


Tout à fait. Dans la pratique, les problèmes de l'integrité
transactionnelle lorsqu'il y a plusieurs utilisateurs en
parallel dominent, mais je ne crois pas que de tels problèmes
fassent partie d'un devoir.

Sur la base d'un tableau d'unsigned char (8-bit), toutes les
extractions/modifications/écritures de champs de taille
quelquonque peuvent être implémentées au besoin.


En fait, il serait probablement bien qu'il définisse des
structures plus élaborer. Mais c'est un des cas exceptionnel où
je concevoir de dumper des structures directement sur disque. Ce
qui est un contraint supplémentaire quand on les conçoit ; on ne
peut dumper que des POSs.

--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34



Avatar
James Kanze
Ivan Vecerina wrote:
"Pascal" wrote in message
news:


[...]
Au niveau du disque dur, les e/s se font en fait même par page
ou secteur, du genre 4k à la fois. Donc si tu écris 1 octet,
le système va typiquement lire le secteur original, y modifier
l'octet, puis écrire le secteur modifié. (Pareil pour 512
octets).


Ce n'est pas vrai en général. Au moins sous Unix, le système
garde les secteurs disque cachés en mémoire ; il ne lit que si
le secteur n'y est pas encore, et il n'écrit que quand bon lui
semble (ce qui explique pourquoi dans des applications robustes,
on est prèsque toujours amené à utiliser des requêtes spéciales,
du genre fsync, on ne travaille que sur les disques locaux,
etc.).

Maintenant, s'il s'amuse à taper un peu n'importe où dans son
fichier, un octet par ci, un octet par là, c'est vrai que si le
fichier est assez grand, il finira par épuiser les possibilités
de cache dans le système, et déclenchera effectivement des
lectures et des écritures. Pour un projet d'école, en revanche,
c'est fort probable qu'un bon Linux finit très vite à garder
tout son fichier en mémoire.

C'est pourquoi les applications optimisées vont utiliser des
pages de données qui correspondent à la taille des secteurs
disque (typiquement 4k).


Pour certaines choses, peut-être. Les contraints de robustesse
ne le permet pas pour tout.

En fait, dans le temps, les bons SGDB avaient tous des options
pour travailler avec un disque brut (/dev/... sous Unix), sans
passer par le système de gestion de fichiers de tout.
Dernièrement ça semble moins démander ; il faut croire que la
gestion interne dans les Unix s'est améliorée.

C'est pourquoi il est très raisonnable de lire ou écrire toute
une page à la fois, et de faire le reste directement en
mémoire.


À mon avis, ça n'a réelement un sens que si on utilise les
requêtes de plus bas niveau ; une fois qu'on a un filebuf ou un
FILE entre son programme et le système, il y a un bufferisation
dont on ne connaît pas trop les effets, mais que s'il est bien
fait, il s'occupe d'assurer l'alignement optimal lui-même (et
s'il est mal fait, il va foutre en l'air l'alignement qu'on
essaie à maintenir dans son programme).

--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34