Search code examples
cfilecsvbinaryfwrite

How to write CSV fields on a binary file?


I have the following code:

typedef struct RegDados{

    char removido; //  deve ser inicializado com '-'
    int encadeamento; // deve ser inicializado com -1
    int nroInscricao; // nao aceita valores repetidos nem nulos
    double nota;
    char data[10]; // checar tipo
    char *cidade;
    int sizecid;
    char tagCampo4;
    char *nomeEscola;
    int sizesch;
    char tagCampo5;
}RegDados;

char * strtokEvenEmpty(char * s, const char * seps){

  static char * p = NULL;

  if (s != NULL)
    p = s;
  else if (p == NULL)
    return NULL;
  else
    s = p;

  while (*p) {
    if (strchr(seps, *p)) {
      *p++ = 0;
      return s;
    }
    p += 1;
  }
  return (*s) ? s : NULL;
}

const char * getfield(char* line, int num){

  const char * tok;

  for (tok = strtokEvenEmpty(line, ","); tok; tok = strtokEvenEmpty(NULL, ",\n")){
    if (!--num)
      return tok;
  }
  return NULL;
}

int main(){

  FILE * stream = fopen("trabalho1.csv.csv", "r+");
  FILE * ArqBin = fopen("test.bin","wb");
  RegDados regdados[5000];
  RegCab regcab;
  int i = 0;

  if(ArqBin == NULL) printf("Error");

  if (stream != NULL) {
    char line[1024];
    while (fgets(line, 1024, stream)) {  

      regdados[i].nroInscricao = atoi(getfield(line, 1));
      fwrite(&regdados[i].nroInscricao, sizeof(int), 1, ArqBin);

      regdados[i].nota =  atof(getfield(line, 2));
      fwrite(&regdados[i].nota, sizeof(double), 1, ArqBin); 

      strcpy(regdados[i].data, getfield(line, 3));                             
      fwrite(regdados[i].data, sizeof(char), 100, ArqBin);  

      regdados[i].cidade = getfield(line, 4);
      fwrite(regdados[i].cidade, sizeof(char), 100, ArqBin);

      regdados[i].nomeEscola = getfield(line, 5);
      fwrite(regdados[i].nomeEscola, sizeof(char), 100, ArqBin);  

      i++;
    }
    fclose(stream);
    fclose(ArqBin);
  }
  else{
    printf("Error");
  }
}

It already parses the fields of my file, but I can't write them on a binary file, because when I try to write, I get a lot of null fields, which doesn't happen when I don't write.

My CSV file looks like:

nroInscricao,nota,data,cidade,nomeEscola

13893,353.9,26/11/2016,,FRANCISCO RIBEIRO CARRIL

13595,472.2,,Salgueiro,ALFREDO GUEDES

13894,614.4,28/11/2016,Recife,JOAO DE MOURA GUIMARAES

13880,403.2,29/11/2016,Fortaleza,ANTONIO DIAS PASCHOAL PR

13881,373.7,,Sao Jose da Tapera,DONIZETTI TAVARES DE LIM

13882,394.8,01/12/2016,Sao Bernardo do Cam,JUSTINO GOMES DE CASTRO

How can I write the each field on a binary file?


Solution

  • when I try to write, I get a lot of null fields, which doesn't happen when I don't write.

    this is normal, the internal representation of number can contains several 0, for instance doing :

    fwrite(&regdados[i].nroInscricao, sizeof(int), 1, ArqBin);
    

    if regdados[i].nroInscricao values 7 and your int are on 32bits that will write 3 times 0 and 1 time 7 (the order depends if you are on little/big endian).

    Of course it is the same with the strings you write with a fixed size, so the padding characters can have any value including 0 (there are not initialized)


    Your way to extract the fields with getfield is expensive because you extract the first token, then to get the second you have to bypass the first token, then to get the third you have to bypass the 2 first tokens etc.

    A better way is to do getfield(line, 1) then getfield(NULL, 1) to get the second token, then to do getfield(NULL, 1) to get the third etc, so in fact the second argument is always 1 and you can remove its management


    You try to open trabalho1.csv.csv, probably you want to open trabalho1.csv


    In

    if(ArqBin == NULL) printf("Error");
    
    if (stream != NULL) {
    

    it is not enough to print error, you must not continue, can be

    if(ArqBin == NULL) 
      printf("Error");
    else if (stream != NULL) {
    

    or better replace

    FILE * stream = fopen("trabalho1.csv.csv", "r+");
    FILE * ArqBin = fopen("test.bin","wb");
    ...
    if(ArqBin == NULL) printf("Error");
    
    if (stream != NULL) {
      ...
    }
    else{
      printf("Error");
    }
    

    by something like

    FILE * stream = fopen("trabalho1.csv.csv", "r+");
    
    if (stream == NULL) {
      fprintf(stderr, "cannot open input file rabalho1.csv.csv");
      return -1;
    }
    
    FILE * ArqBin = fopen("test.bin","wb");
    
    if (ArqBin == NULL) {
      fprintf(stderr, "cannot open output file test.bin");
      fclose(stream); /* really useful if you do not stop execution */
      return -1;
    }
    ...