Y a-t-il un danger à écrire des octets bruts dans un fichier? [fermé]

12

Je travaille sur un problème de programmation des perles - en particulier, la mise en œuvre d'un programme qui trie un fichier contenant, au plus, 10 000 000 entiers (colonne 1, problème 3). Étant donné que le livre ne précise pas comment les données doivent être stockées dans le fichier, j'envisage de stocker les entiers sous forme d'octets bruts (il existe d'autres contraintes qui font des octets bruts une bonne option). Je n'ai jamais travaillé à ce niveau inférieur auparavant, donc je veux savoir s'il y a quelque chose de dangereux à surveiller. Dois-je m'inquiéter de l'utilisation accidentelle d'une sorte de séquence de fin de fichier lorsque j'écris des octets bruts dans un fichier, par exemple?

Éditer:

Je réalise maintenant à quel point ma question était large. Je voulais vraiment dire des problèmes plus catastrophiques, comme écraser accidentellement d'autres fichiers sur le disque. Désolé, je n'étais pas plus clair à l'origine.

Drake Sobania
la source
6
Notez que Programming Pearls est un livre très ancien; vous pouvez facilement lire l'intégralité des 10 ^ 7 entiers en mémoire sur une machine de bureau moderne, faire le tri et le réécrire. Pour obtenir le point d'origine de ce chapitre, limitez la quantité que vous lisez à tout moment à une fraction du nombre total. Ou augmentez la taille du fichier à environ 10 ^ 10 entiers.
Caleb
3
En fait, quand j'entends le mot "dangereux", je pense à des choses qui font exploser mon PC, effacent mes comptes bancaires ou quelque chose comme ça. Et je suppose qu'il est très probable de supposer que - tant que votre programme n'est pas utilisé pour contrôler un Airbus ou une centrale électrique - rien de vraiment «dangereux» ne se produira lorsque vous essayez ce que vous avez en tête.
Doc Brown
2
@delnan Il y a des années, quand le mythe du personnage EOF était en vogue, je me souviens des systèmes de protection contre la copie qui étaient basés sur la «copie jusqu'au caractère EOF» que beaucoup de programmes de copie de l'époque faisaient. Certains programmes mettraient des données supplémentaires qu'ils vérifieraient après le marqueur EOF d'un fichier texte associé, mais avant la fin allouée du fichier. Le programme de copie ne copierait pas les données supplémentaires validant une installation propre ... ahh ... la nostalgie.
danger? Comme dans "mon ordinateur va-t-il exploser si je fais ça"? Nan.
jwenting

Réponses:

11

Le seul danger que vous rencontrerez est le petit ou le gros caractère (que l'octet le plus ou le moins significatif soit écrit en premier). Cependant, si vous restez dans le même environnement, il n'y aura aucun problème. outre la garantie générale d'écriture / analyse de l'aller-retour.

Le système de fichiers est conçu pour gérer n'importe quelle séquence d'octets.

monstre à cliquet
la source
2
+1 pour la dernière ligne. Je ne suis pas sûr que le gros / petit problème soit le seul problème - l'OP pourrait par exemple être confus quant à la position des frontières entre les entiers. Mais bonne réponse quand même.
Caleb
27

Non, c'est en fait le nombre de formats de fichiers qui fonctionnent. Des exemples courants de fichiers binaires comme celui-ci incluent des images et des fichiers audio / musicaux.

Pour maintenir l'intégrité du fichier et des données qui y sont lues, veillez à suivre ces instructions:

  • Ouvrez toujours le fichier (lecture ou écriture) en utilisant le même mode: texte ou binaire. La principale différence est que le mode texte se soucie des sauts de ligne et peut "couper" les caractères de retour à la ligne lors de la lecture d'un fichier (en fonction de la bibliothèque spécifique utilisée). Le mode texte peut également effectuer des traductions Unicode qui s'étoufferont probablement sur les données non Unicode.
  • Lors de la lecture de données non-chaîne, assurez-vous de lire en utilisant le même type de données que vous écrivez. Par exemple, si les quatre premiers octets du fichier sont un entier descriptif, assurez-vous de lire et d'écrire en utilisant une méthode qui prend / fournit un entier pour vous assurer qu'il est traité de manière cohérente. Le même type de données peut avoir une taille différente sur différentes machines, et le mélange de types de données sur la même machine peut également changer la signification des données (par exemple, interpréter un bit au milieu d'un entier plus long comme bit de signe).
  • Endianness: si la bibliothèque que vous utilisez ne gère pas cela de manière cohérente, vous devrez peut-être la gérer vous-même. Par exemple, Java utilise toujours l'ordre des octets réseau (big endian) pour les types multi-octets. C et C ++ utilisent tout ce que l'implémenteur de bibliothèque a décidé, généralement le même que le processeur (petit endian sur Intel, gros endian sur la plupart des autres). S'il s'agit d'un exercice rapide sur un système, ce n'est pas aussi important, mais c'est toujours une bonne habitude d'y prêter attention et de le coder si nécessaire.

Les détails spécifiques varieront en fonction du cadre, de la plate-forme et du langage, mais cela devrait couvrir les "pièges" de base avec les E / S de fichiers.


la source
3
Un point supplémentaire pour les données non-chaîne: assurez-vous que vous utilisez un nombre cohérent d'octets pour chaque type. En C et C ++ an intpeut être n'importe où entre 2 et 8 octets ou plus (octets vraiment).
Bart van Ingen Schenau du
Cela est implicitement inclus avec mon deuxième point, par exemple un entier 32 contre 64 bits. Il s'agirait de différents types de données.
Vous voudrez peut-être le rendre explicite. Il n'est pas évident que intsur deux machines différentes puissent être considérées comme des types de données différents.
Bart van Ingen Schenau
9

En plus de tous les pièges déjà mentionnés, si vous créez un nouveau format de fichier binaire plutôt que de lire et d'écrire des données dans un format existant, il est absolument vital d'inclure un en-tête de fichier : un bloc de données au tout début du fichier qui identifie sans ambiguïté le format de fichier et enregistre toutes les métadonnées qui peuvent être nécessaires.

Les bons en-têtes de fichiers comprennent au moins trois éléments:

  • Un " nombre magique ", d'au moins quatre octets. Le nombre magique DOIT rfc2119 être les tout premiers N octets du fichier, NE DOIT jamais avoir été utilisé pour tout autre format de fichier que vous pouvez rechercher, et DOIT contenir au moins un octet qui n'est pas un caractère ASCII imprimable. Voir la spécification PNG pour savoir comment concevoir un nombre magique vraiment complet . Voir le code source de la file(1)commande pour une base de données de nombres magiques existants qui est aussi complète que vous êtes susceptible de trouver.

    L'intérêt d'un nombre magique est d'étiqueter sans ambiguïté le fichier, dans la bande, avec son format. Si vous n'incluez pas de nombre magique, ou si ce n'est pas la toute première chose dans le fichier, vous courez le risque que des programmes identifient mal votre fichier comme un autre type de fichier, ce qui entraîne une perte de données, des virus échappant à la détection , etc. catastrophes.

  • Une indication de la version du format de fichier. Même si vous pensez que vous n'aurez jamais à réviser votre format de fichier de manière drastique, faites les deux octets suivants après le nombre magique 00 00et documentez qu'il s'agit d'un numéro de version 16 bits dans une certaine finesse définie (selon ce que vous voulez, mais choisissez un et respectez-le tout au long du fichier ) et sera incrémenté si la signification des données suivantes change radicalement. Votre futur moi vous remerciera.

    (La spécification PNG prend un itinéraire différent ici, spécifiant que les formats de bloc sont figés et que toutes les futures modifications du format prendront la forme de nouveaux types de bloc. C'est également valide, mais je recommande l'approche simple du nombre magique + du numéro de version pour les débutants au traitement de données binaires. Les concepteurs de PNG s'appuyaient sur des décennies d'expérience collective avec les formats d'image.)

  • Une sorte de mécanisme pour incorporer des métadonnées arbitraires dans le fichier. Cela peut être aussi simple que d' avoir les prochains deux octets être un 16 bits décalé par rapport à la fin de l' en- tête au début des données réelles, avec tout le reste à interpréter comme paires UTF-8 clé-valeur une RFC la 822 (c'est-à-dire " Tag: value\n" - si vous suivez cette voie, je recommande de ne pas autoriser le pliage de longues lignes). Encore une fois, PNG est considérablement plus intelligent.

zwol
la source
Pas besoin de créer votre propre format de fichier ... il suffit de stocker les données sous forme d'image. Vous devrez peut-être modifier la dimensionnalité (par exemple, 10k x 1k) afin qu'elle soit prise en charge. Ou vous pouvez utiliser FITS . Si vos données sont plus complexes qu'une simple baie, vous pouvez utiliser HDF , CDF ou NetCDF .
Joe
Je suggère de rester simple. 256 versions différentes suffiront et sinon, des versions supplémentaires peuvent être conçues comme des sous-versions de la version 255. De même pour les métadonnées, il suffit de les ajouter dans la version quand elles sont réellement nécessaires. @Joe Image ??? Vous évitez la confusion potentielle de format en déroutant tout le monde à l'avance!
maaartinus
@maaartinus Rendre le champ de version de deux octets force le concepteur de format à s'engager dès le départ pour une endianité. L'espace pour les métadonnées doit toujours être dans la version 0 d'un format binaire, sinon vous vous retrouvez avec d'horribles kludges comme ID3. J'ai beaucoup de sympathie pour la logique de la spécification PNG concernant l'extensibilité via de nouveaux types de blocs au lieu de bumps de version de format. Cependant, les fichiers structurés en morceaux apportent leur propre complexité, donc j'hésite à les recommander pour des cas simples. J'ai été tenté de recommander HDF comme format générique qui traitait déjà beaucoup de ces problèmes.
zwol
2

Différentes architectures ont des représentations différentes pour les entiers. Le principal risque ici est d'enregistrer la représentation en octets d'un entier dans la machine A, puis d'essayer de le lire et d'interpréter le contenu comme des entiers dans la machine B.Si les machines A et B ont des tailles différentes pour les entiers et / ou une endianité différente , vous '' ll provoquera très probablement un comportement indéfini (par exemple en C) ou une exception.

Comme ce n'est qu'un exemple de programmation et non un "vrai" programme, ce n'est pas vraiment un problème. S'il s'agissait d'un vrai programme, rouler votre propre format binaire spécifique à l'application n'est généralement pas une bonne idée; il existe de meilleures solutions, comme SQLite ou des formats de sérialisation basés sur des chaînes comme JSON, YAML, XML, etc. Pour des valeurs uniques, la transformer en chaîne suffirait; pour les listes simples, vous pouvez enregistrer une chaîne par ligne et simplement diviser l'entrée sur les nouvelles lignes lorsque vous la relisez.

Doval
la source
D'accord en général, mais JSON ou XML augmenterait considérablement la taille d'un fichier contenant 10 ^ 7 chiffres. En outre, ils sont généralement lus et analysés en même temps, mais le chapitre en question traite du tri des fichiers contenant plus de données que vous ne pouvez en contenir dans la mémoire disponible.
Caleb
Cela dépend de ce que vous faites. Parfois, la performance de SQL contre un roll-your-own est majeure. La dernière fois que je l'ai fait, j'avais de petits records et il y avait de fortes chances que je veuille des voisins. Lire un bloc plus gros sur le disque ne coûterait généralement presque rien, donc si je voulais un enregistrement, je lis 1000 dans un cache. Mes enregistrements étaient presque certainement côte à côte, avec SQL la tête de disque rebondirait partout.
Loren Pechtel