Quelqu'un a-t-il un exemple de code qui peut écrire dans un fichier binaire ? Et aussi un code qui peut lire un fichier binaire et l'afficher à l'écran. En regardant les exemples, je peux écrire dans un fichier sans problème, mais lorsque j'essaie de lire un fichier, la sortie ne se fait pas correctement.
Réponses
Trop de publicités?La lecture et l'écriture de fichiers binaires sont à peu près les mêmes que pour n'importe quel autre fichier, la seule différence étant la manière dont vous l'ouvrez :
unsigned char buffer[10];
FILE *ptr;
ptr = fopen("test.bin","rb"); // r for read, b for binary
fread(buffer,sizeof(buffer),1,ptr); // read 10 bytes to our buffer
Vous avez dit que vous pouviez le lire, mais qu'il ne sortait pas correctement... Gardez à l'esprit que lorsque vous "sortez" ces données, vous ne lisez pas de l'ASCII, ce n'est donc pas comme si vous imprimiez une chaîne de caractères à l'écran :
for(int i = 0; i<10; i++)
printf("%u ", buffer[i]); // prints a series of bytes
L'écriture dans un fichier est à peu près la même, à l'exception du fait que vous utilisez la fonction fwrite()
au lieu de fread()
:
FILE *write_ptr;
write_ptr = fopen("test.bin","wb"); // w for write, b for binary
fwrite(buffer,sizeof(buffer),1,write_ptr); // write 10 bytes from our buffer
Puisque nous parlons de Linux, il y a un moyen facile de faire une vérification. Installer hexdump
sur votre système (si ce n'est pas déjà le cas) et vidanger votre fichier :
mike@mike-VirtualBox:~/C$ hexdump test.bin
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0001 003e 0001 0000 0000 0000 0000 0000
...
Comparez maintenant ce résultat à votre production :
mike@mike-VirtualBox:~/C$ ./a.out
127 69 76 70 2 1 1 0 0 0
hmm, peut-être changer le printf
à un %x
pour que ce soit un peu plus clair :
mike@mike-VirtualBox:~/C$ ./a.out
7F 45 4C 46 2 1 1 0 0 0
Hé, regardez ! Les données correspondent maintenant * . Génial, nous devons lire le fichier binaire correctement !
*Notez que les octets sont simplement échangés sur la sortie mais que les données sont correctes, vous pouvez ajuster pour ce genre de choses.
Il y a plusieurs façons de procéder. Si je veux lire et écrire du binaire, j'utilise généralement open()
, read()
, write()
, close()
. Ce qui est complètement différent de faire un octet à la fois. Vous travaillez avec des descripteurs de fichiers entiers au lieu de variables FILE *. fileno obtiendra un descripteur entier à partir d'un FILE * BTW. Vous lisez un tampon plein de données, disons 32k octets en une seule fois. Le tampon est en fait un tableau que vous pouvez lire très rapidement parce qu'il est en mémoire. La lecture et l'écriture de plusieurs octets à la fois sont plus rapides que la lecture d'un seul octet à la fois. C'est ce qu'on appelle une lecture en bloc en Pascal, je crois, mais read() est l'équivalent en C.
J'ai cherché, mais je n'ai pas d'exemples sous la main. D'accord, ces exemples ne sont pas idéaux parce qu'ils font aussi des choses avec des images JPEG. Voici une lecture, vous ne vous intéressez probablement qu'à la partie allant de open() à close(). fbuf est le tableau dans lequel lire, sb.st_size est la taille du fichier en octets à partir d'un appel à stat().
fd = open(MASKFNAME,O_RDONLY);
if (fd != -1) {
read(fd,fbuf,sb.st_size);
close(fd);
splitmask(fbuf,(uint32_t)sb.st_size); // look at lines, etc
have_mask = 1;
}
Voici une écriture : (ici pix est le tableau d'octets, jwidth et jheight sont la largeur et la hauteur du JPEG, donc pour une couleur RGB nous écrivons hauteur * largeur * 3 octets de couleur). C'est le nombre d'octets à écrire.
void simpdump(uint8_t *pix, char *nm) { // makes a raw aka .data file
int sdfd;
sdfd = open(nm,O_WRONLY | O_CREAT);
if (sdfd == -1) {
printf("bad open\n");
exit(-1);
}
printf("width: %i height: %i\n",jwidth,jheight); // to the console
write(sdfd,pix,(jwidth*jheight*3));
close(sdfd);
}
Regardez l'homme 2 ouvrir, aussi lire, écrire, fermer. Regardez aussi ce vieux style de jpeg example.c : https://github.com/LuaDist/libjpeg/blob/master/example.c Je suis en train de lire et d'écrire une image entière en même temps. Mais il s'agit de lectures et d'écritures binaires d'octets, mais beaucoup à la fois.
"Mais lorsque j'essaie de lire un fichier, la sortie n'est pas correcte." Hmmm. Si vous lisez un nombre 65, c'est l'ASCII (décimal) pour un A. Peut-être devriez-vous regarder man ascii aussi. Si vous voulez un 1, c'est l'ASCII 0x31. Une variable char est un minuscule entier de 8 bits, si vous faites un printf comme %i vous obtenez la valeur ASCII, si vous faites un %c vous obtenez le caractère. Faites %x pour l'hexadécimal. Tous les chiffres sont identiques et se situent entre 0 et 255.
Je suis assez satisfait de ma solution qui consiste à créer un programme de stockage d'épingles faibles. Peut-être que cela aidera les gens qui ont besoin d'un exemple très simple d'IO de fichier binaire à suivre.
$ ls
WeakPin my_pin_code.pin weak_pin.c
$ ./WeakPin
Pin: 45 47 49 32
$ ./WeakPin 8 2
$ Need 4 ints to write a new pin!
$./WeakPin 8 2 99 49
Pin saved.
$ ./WeakPin
Pin: 8 2 99 49
$
$ cat weak_pin.c
// a program to save and read 4-digit pin codes in binary format
#include <stdio.h>
#include <stdlib.h>
#define PIN_FILE "my_pin_code.pin"
typedef struct { unsigned short a, b, c, d; } PinCode;
int main(int argc, const char** argv)
{
if (argc > 1) // create pin
{
if (argc != 5)
{
printf("Need 4 ints to write a new pin!\n");
return -1;
}
unsigned short _a = atoi(argv[1]);
unsigned short _b = atoi(argv[2]);
unsigned short _c = atoi(argv[3]);
unsigned short _d = atoi(argv[4]);
PinCode pc;
pc.a = _a; pc.b = _b; pc.c = _c; pc.d = _d;
FILE *f = fopen(PIN_FILE, "wb"); // create and/or overwrite
if (!f)
{
printf("Error in creating file. Aborting.\n");
return -2;
}
// write one PinCode object pc to the file *f
fwrite(&pc, sizeof(PinCode), 1, f);
fclose(f);
printf("Pin saved.\n");
return 0;
}
// else read existing pin
FILE *f = fopen(PIN_FILE, "rb");
if (!f)
{
printf("Error in reading file. Abort.\n");
return -3;
}
PinCode pc;
fread(&pc, sizeof(PinCode), 1, f);
fclose(f);
printf("Pin: ");
printf("%hu ", pc.a);
printf("%hu ", pc.b);
printf("%hu ", pc.c);
printf("%hu\n", pc.d);
return 0;
}
$
Il s'agit d'un exemple de lecture et d'écriture d'un fichier vidéo binaire jjpg ou wmv. FILE *fout ; FILE *fin ;
Int ch;
char *s;
fin=fopen("D:\\pic.jpg","rb");
if(fin==NULL)
{ printf("\n Unable to open the file ");
exit(1);
}
fout=fopen("D:\\ newpic.jpg","wb");
ch=fgetc(fin);
while (ch!=EOF)
{
s=(char *)ch;
printf("%c",s);
ch=fgetc (fin):
fputc(s,fout);
s++;
}
printf("data read and copied");
fclose(fin);
fclose(fout);
Cette question est liée à la question Comment écrire un fichier de données binaires en C et le tracer à l'aide de Gnuplot ? par CAMILO HG. Je sais que le problème réel comporte deux parties : 1) Ecrire le fichier de données binaires, 2) Le tracer à l'aide de Gnuplot.
La première partie a reçu une réponse très claire ici, je n'ai donc rien à ajouter.
Pour la seconde, la solution la plus simple est d'envoyer les gens vers le manuel Gnuplot, et je suis sûr que quelqu'un trouvera une bonne réponse, mais je ne la trouve pas sur le web, donc je vais expliquer une solution (qui doit être dans la vraie question, mais je ne connais pas stackoverflow et je ne peux pas y répondre) :
Après avoir écrit votre fichier de données binaires à l'aide de fwrite()
Vous devez créer un programme très simple en C, un lecteur. Le lecteur ne contient que la même structure que l'auteur, mais vous utilisez fread()
au lieu de fwrite()
. Il est donc très facile de générer ce programme : copiez dans le fichier reader.c
fichier la partie écriture de votre code original et remplacez write par read (et "wb" par "rb"). En outre, vous pourriez inclure quelques vérifications pour les données, par exemple, si la longueur du fichier est correcte. Enfin, votre programme doit imprimer les données sur la sortie standard à l'aide d'une fonction printf()
.
Pour être clair : votre programme se déroule comme suit
$ ./reader data.dat
X_position Y_position (it must be a comment for Gnuplot)*
1.23 2.45
2.54 3.12
5.98 9.52
D'accord, avec ce programme, dans Gnuplot, il suffit d'envoyer la sortie standard du lecteur vers Gnuplot, quelque chose comme ceci :
plot '< ./reader data.dat'
Cette ligne exécute le programme reader, et la sortie est connectée à Gnuplot qui trace les données.
*Parce que Gnuplot va lire la sortie du programme, vous devez savoir ce que Gnuplot peut lire et tracer et ce qui ne peut pas l'être.
- Réponses précédentes
- Plus de réponses