Lees en schrijf naar binaire bestanden in C?

Heeft iemand een voorbeeld van code die naar een binair bestand kan schrijven. En ook code die een binair bestand kan lezen en naar het scherm kan uitvoeren. Als ik naar voorbeelden kijk, kan ik naar een bestand schrijven, maar als ik probeer te lezen uit een bestand, wordt het niet correct uitgevoerd.


Antwoord 1, autoriteit 100%

Het lezen en schrijven van binaire bestanden is vrijwel hetzelfde als elk ander bestand, het enige verschil is hoe je het opent:

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

Je zei dat je het kunt lezen, maar het wordt niet correct uitgevoerd… houd er rekening mee dat wanneer je deze gegevens “uitvoert”, je geen ASCII leest, dus het is niet alsof je een string op het scherm afdrukt:

p>

for(int i = 0; i<10; i++)
    printf("%u ", buffer[i]); // prints a series of bytes

Het schrijven naar een bestand is vrijwel hetzelfde, met de uitzondering dat je fwrite()in plaats van 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

Omdat we het over Linux hebben… is er een gemakkelijke manier om een gezond verstand te controleren. Installeer hexdumpop je systeem (als het daar nog niet staat) en dump je bestand:

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
...

Vergelijk dat nu met je output:

mike@mike-VirtualBox:~/C$ ./a.out 
127 69 76 70 2 1 1 0 0 0

hmm, verander misschien de printfin een %xom dit een beetje duidelijker te maken:

mike@mike-VirtualBox:~/C$ ./a.out 
7F 45 4C 46 2 1 1 0 0 0

Hé, kijk! De gegevens komen nu overeen*. Geweldig, we moeten het binaire bestand correct lezen!

*Let op de bytes zijn gewoon verwisseld op de uitvoer, maar die gegevens zijn correct, je kunt dit soort dingen aanpassen


Antwoord 2, autoriteit 3%

Er zijn een paar manieren om dit te doen. Als ik binair wil lezen en schrijven, gebruik ik meestal open(), read(), write(), close(). Wat totaal anders is dan een byte tegelijk doen. Je werkt met integer bestandsdescriptors in plaats van FILE * variabelen. fileno krijgt een integer descriptor van een FILE * BTW. Je leest een buffer vol gegevens, zeg 32k bytes tegelijk. De buffer is echt een array waar je heel snel uit kunt lezen omdat hij in het geheugen zit. En het lezen en schrijven van veel bytes tegelijk is sneller dan één tegelijk. Het wordt een blockread genoemd in Pascal denk ik, maar read() is het C-equivalent.

Ik heb gekeken, maar ik heb geen voorbeelden bij de hand. Oké, deze zijn niet ideaal omdat ze ook dingen doen met JPEG-afbeeldingen. Hier is een read, je geeft waarschijnlijk alleen om het deel van open() tot close(). fbuf is de array om in te lezen,
sb.st_size is de bestandsgrootte in bytes van een stat()-aanroep.

   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;
    }

Hier is een schrijven: (hier is pix de byte-array, jwidth en jheight zijn de JPEG-breedte en -hoogte, dus voor RGB-kleuren schrijven we hoogte * breedte * 3 kleurbytes). Het is het aantal bytes dat moet worden geschreven.

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);
}

Kijk naar man 2 open, ook lezen, schrijven, sluiten. Ook dit oude jpeg-voorbeeld.c: https://github.com/ LuaDist/libjpeg/blob/master/example.cIk lees en schrijf hier een hele afbeelding tegelijk. Maar het zijn binaire lees- en schrijfbewerkingen van bytes, gewoon veel tegelijk.

“Maar als ik uit een bestand probeer te lezen, wordt het niet correct uitgevoerd.” Hmmm. Als je een getal 65 leest, is dat (decimaal) ASCII voor een A. Misschien moet je ook naar man ascii kijken. Als u een 1 wilt, is dat ASCII 0x31. Een char-variabele is eigenlijk een klein 8-bits geheel getal, als je een printf als een %i doet, krijg je de ASCII-waarde, als je een %c doet, krijg je het teken. Voer %x uit voor hexadecimaal. Allemaal van hetzelfde nummer tussen 0 en 255.


Antwoord 3

Ik ben best tevreden met mijn “maak een zwakke pin-opslagprogramma”-oplossing. Misschien helpt het mensen die een heel eenvoudig binair bestand IO-voorbeeld nodig hebben om te volgen.

$ 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;
}
$

Antwoord 4

Dit is een voorbeeld om binair JJPG- of WMV-videobestand te lezen en te schrijven.
Bestand * fout;
Bestand * 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);

Antwoord 5

Ik had echt moeite om een manier te vinden om een binair bestand in een byte-array in C++ te lezen die dezelfde hex-waarden zou opleveren die ik in een hex-editor zie. Na veel vallen en opstaan lijkt dit de snelste manier om dit te doen zonder extra casts. Standaard laadt het het hele bestand in het geheugen, maar drukt alleen de eerste 1000 bytes af.

string Filename = "BinaryFile.bin";
FILE* pFile;
pFile = fopen(Filename.c_str(), "rb");
fseek(pFile, 0L, SEEK_END);
size_t size = ftell(pFile);
fseek(pFile, 0L, SEEK_SET);
uint8_t* ByteArray;
ByteArray = new uint8_t[size];
if (pFile != NULL)
{
    int counter = 0;
    do {
        ByteArray[counter] = fgetc(pFile);
        counter++;
    } while (counter <= size);
    fclose(pFile);
}
for (size_t i = 0; i < 800; i++) {
    printf("%02X ", ByteArray[i]);
}

Antwoord 6

deze vraag is gekoppeld aan de vraag Hoe een binair gegevensbestand op C te schrijven en het te plotten met Gnuplotvan CAMILO HG. Ik weet dat het echte probleem uit twee delen bestaat: 1) Schrijf het binaire gegevensbestand, 2) Plot het met Gnuplot.

Het eerste deel is hier heel duidelijk beantwoord, dus ik heb niets toe te voegen.

Voor de tweede is de eenvoudige manier de mensen naar de GNUPLOT-handleiding verstuurd, en ik weet zeker dat iemand een goed antwoord vindt, maar ik vind het niet op het web, dus ik ga een oplossing uitleggen (die moet zijn In de echte vraag, maar ik ben nieuw in Stackoverflow en ik kan daar niet beantwoorden):

Nadat u uw binair gegevensbestand wilt schrijven met fwrite(), moet u een zeer eenvoudig programma in C, een lezer maken. De lezer bevat alleen dezelfde structuur als de schrijver, maar u gebruikt fread()in plaats daarvan fwrite(). Het is dus erg gemak om dit programma te genereren: kopiëren in de reader.cBestand het schrijfgedeelte van uw originele code en wijzig het schrijven voor lees (en “WB” voor “RB”). Bovendien zou u bijvoorbeeld enkele controles voor de gegevens kunnen opnemen, bijvoorbeeld als de lengte van het bestand correct is. En ten slotte moet uw programma de gegevens in de standaarduitvoer afdrukken met behulp van een printf().

Wees duidelijk: uw programma loopt dit

$ ./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

Okey, met dit programma, in GNUPLOT, hoeft u alleen de standaarduitvoer van de lezer naar de GNUPLOT te pijpen, zoiets:

plot '< ./reader data.dat'

Met deze regel, voer de programmadoerader uit en de uitvoer is verbonden met GNUPLOT en het plotten de gegevens.

* Omdat GNUPLOT de uitvoer van het programma zal lezen, moet u weten wat kan GNUPLOT lezen en plot en wat niet kan.

Other episodes